pike.git / lib / modules / Tools.pmod / Standalone.pmod / test_pike.pike

version» Context lines:

pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:1:   #! /usr/bin/env pike   #pike __REAL_VERSION__      constant description = "Executes tests according to testsuite files.";    - constant log_msg = Tools.Testsuite.log_msg; - constant log_msg_cont = Tools.Testsuite.log_msg_cont; - constant log_status = Tools.Testsuite.log_status; + import Tools.Testsuite;      protected enum exit_codes {    EXIT_OK,    EXIT_TEST_FAILED,    EXIT_TEST_NOT_FOUND,    EXIT_WATCHDOG_FAILED,   };      #if !constant(_verify_internals)   #define _verify_internals()   #endif    - #if !constant(_dmalloc_set_name) - void _dmalloc_set_name(mixed ... args) {} - #endif -  +    int foo(string opt)   {    if(opt=="" || !opt) return 1;    return (int)opt;   }      int maybe_tty = 1;      mapping(string:int) cond_cache=([]);      #if constant(thread_create)   #define HAVE_DEBUG   #endif      void print_code(string test)   { -  array lines = Charset.encoder("iso-8859-1", 0, +  test = Charset.encoder("iso-8859-1", 0,    lambda(string s) {    return sprintf("\\%o", s[0]); -  })->feed(test)->drain()/"\n"; -  foreach(lines; int r; string line) { +  })->feed(test)->drain(); +  foreach(test/"\n"; int r; string line) {    log_msg("%3d: %s\n", r+1, line);    }    log_msg("\n"); -  return; +    }      void report_size()   {   #if 0    Process.system(sprintf("/usr/proc/bin/pmap %d|tail -1", getpid()));   #endif   }    - array find_testsuites(string dir) + array(string) find_testsuites(string dir)   { -  array(string) ret=({}); -  if(array(string) s=get_dir(dir||".")) +  array(string) ret = ({}); +  if(array(string) s = get_dir(dir))    { -  if(has_value(s,"no_testsuites")) return ret; +  if(has_value(s, "no_testsuites")) return ret;    foreach(s, string file)    { -  string name=combine_path(dir||"",file); -  if(Stdio.is_dir(name)) { -  ret+=find_testsuites(name); -  continue; +  string name = combine_path(dir, file); +  if(Stdio.is_dir(name)) +  ret += find_testsuites(name); +  else if(file=="testsuite") { +  ret += ({ combine_path(dir, file) }); +  } else if(has_suffix(file, ".test")) { +  ret += ({ combine_path(dir, file) });    } -  switch(file) +  } +  } +  return ret; + } +  + class ScriptTestsuite(string file_name)   { -  case "testsuite": -  case "module_testsuite": -  ret+=({ combine_path(dir||"",file) }); +  inherit Testsuite; +  protected int(1..1) _sizeof() { return 1; } +  protected this_program `+(mixed steps) +  { +  if(steps) file_name = 0; +  return this;    } -  +  protected int(0..1) `!() { return !file_name; } +  int(0..0) next() +  { +  file_name = 0; +  return 0;    } -  +  int(0..) index() { return 0; } +  Test value() +  { +  return Test(file_name, 1, 1, "RUNCT", +  sprintf("array a() { return Tools.Testsuite.run_script (({ %q })); }", file_name));    } -  return ret; +    }    - array(string|array(string)) read_tests( string fn ) { -  string|array(string) tests = Stdio.read_file( fn ); + Testsuite read_tests( string fn ) { +  string tests = Stdio.read_file( fn );    if(!tests) {    log_msg("Failed to read test file %O, errno=%d.\n",    fn, errno());    exit(EXIT_TEST_NOT_FOUND);    }    -  string pike_compat; -  if(sscanf (tests, "START%s\n%s", pike_compat, tests) == 2) { -  if(!has_suffix(tests, "END\n")) -  log_msg("%s: Missing end marker.\n", fn); -  else -  tests = tests[..<sizeof ("END\n")]; -  pike_compat = String.trim_whites (pike_compat); -  if (pike_compat == "") pike_compat = 0; -  } +  string test_type = "legacy"; +  sscanf(tests, "%*sTEST:%*[ \t]%s%*[ \t\n]", test_type); +  if (test_type == "RUN-AS-PIKE-SCRIPT") +  return ScriptTestsuite(fn);    -  tests = tests/"\n....\n"; -  return ({pike_compat, tests[..<1]}); +  tests = String.trim(tests); +  if(!sizeof(tests)) return 0; +  +  if( fn=="testsuite" || has_suffix(fn, "/testsuite") ) +  return M4Testsuite(tests, fn); +  +  log_msg("Unable to make sense of test file %O.\n", fn); +  return 0;   }      mapping(string:int) pushed_warnings = ([]);      class WarningFlag {    int(0..1) warning;    array(string) warnings = ({});       void compile_warning(string file, int line, string text) {    if (pushed_warnings[text]) return;    if (sizeof(filter(indices(pushed_warnings), glob, text))) return;    warnings += ({ sprintf("%s:%d: %s", file, line, text) });    warning = 1;    }    -  +  void write_warnings(string fname, string source) +  { +  log_msg("%s produced warning.\n" +  "%{%s\n%}", fname, warnings); +  print_code(source); +  } +     void compile_error(string file, int line, string text) {    log_msg("%s:%d: %s\n", file,line,text);    }   }      //   // Watchdog stuff   //      #ifndef WATCHDOG_TIMEOUT - // 20 minutes should be enough.. + // 40 minutes should be enough...   #if !constant(_reset_dmalloc) - #define WATCHDOG_TIMEOUT 60*20 + #define WATCHDOG_TIMEOUT 60*40   #else   // ... unless we're running dmalloc - #define WATCHDOG_TIMEOUT 60*80 + #define WATCHDOG_TIMEOUT 60*160   #endif   #endif      // FIXME: Should make WATCHDOG_TIMEOUT even larger when running in valgrind.      #define WATCHDOG_MSG(fmt, x...) log_msg ("[WATCHDOG]: " fmt, x)      #if 0   #define WATCHDOG_DEBUG_MSG(fmt, x...) WATCHDOG_MSG (fmt, x)   #else
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:162:      void watchdog_new_pid (int pid)   {    if (use_watchdog)    send_watchdog_command ("pid %d", pid);   }      void watchdog_start_new_test (string current_test, mixed... args)   // Tells the watchdog that a new test is about to be run. This clears   // the test output buffer if the watchdog is buffering stdout (i.e. is - // not running in verbose mode) . + // not running in verbose mode).   {    if (use_watchdog)    send_watchdog_command ("cur " + current_test, @args);   }      void watchdog_show_last_test()   // If the watchdog buffers stdout instead of sending it on right away   // then this will make it send the output from the last test,   // including timestamps at the beginning of each line. Each test is   // only shown once.
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:186:   }      class Watchdog   {    Stdio.File stdin;    int parent_pid, watched_pid;    string stdout_buf = "", current_test;    int verbose, timeout_phase;    int start_time = time();    -  protected inherit Tools.Testsuite.WatchdogFilterStream; +  protected inherit WatchdogFilterStream;       string format_timestamp()    {    int t = time() - start_time;    return sprintf ("%02d:%02d:%02d", t / 3600, t / 60 % 60, t %60);    }       void stdin_read (mixed ignored, string in)    {    WATCHDOG_DEBUG_MSG ("Reset timeout at %s", ctime (time()));
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:250:    stdout_buf += in;    while (sizeof (stdout_buf) > 100000 &&    sscanf (stdout_buf, "%*s\n%s", stdout_buf) == 2) {}    }    }    }       void stdin_close (mixed ignored)    {    if (stdin->errno()) { -  WATCHDOG_MSG ("Error reading stdin pipe: %s\n", +  WATCHDOG_MSG ("Error reading stdin pipe: %s.\n",    strerror (stdin->errno()));    }    _exit(EXIT_OK);    }       void check_parent_pid()    {    if (!kill (parent_pid, 0)) {    WATCHDOG_DEBUG_MSG ("Parent process %d gone - exiting\n", parent_pid);    _exit(EXIT_OK);
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:345:    mixed err = catch { stdin_read(0, data); };    if (err) master()->report_error(err);    }    mixed err = catch { stdin_close(0); };    if (err) master()->report_error(err);    }       void create (int pid, int verbose)    {    parent_pid = watched_pid = pid; -  this_program::verbose = verbose; +  this::verbose = verbose;    WATCHDOG_DEBUG_MSG ("Watchdog started.\n");    stdin = Stdio.File ("stdin");   #ifdef __NT__   #if constant(thread_create)    // Non-blocking I/O on non-sockets is not supported on NT.    // Simulate with a thread that performs a blocking read.    thread_create(reader_thread, stdin);   #endif   #else /* !__NT__ */    stdin->set_nonblocking (stdin_read, 0, stdin_close);   #endif /* __NT__ */    call_out (check_parent_pid, 10);    call_out (timeout, WATCHDOG_TIMEOUT);    }   }    - string find_test(string ts) + array(string) find_test(string ts)   {    if(Stdio.is_file(ts)) -  return ts; +  return ({ ts });    if(Stdio.is_dir(ts)) -  return combine_path(ts, "testsuite"); +  return find_testsuites(ts);       // Let's DWIM    string try;    if(Stdio.is_file(try="tlib/modules/"+replace(ts, ".", ".pmod/")+".pmod/testsuite")) -  return try; -  if(Stdio.is_file(try="modules/"+ts+"/testsuite")) return try; -  if(Stdio.is_file(try="post_modules/"+ts+"/testsuite")) return try; -  return ts; +  return ({ try }); +  if(Stdio.is_file(try="../../lib/modules/"+replace(ts, ".", ".pmod/")+".test")) +  return ({ try }); +  if(Stdio.is_file(try="modules/"+ts+"/testsuite")) return ({ try }); +  if(Stdio.is_file(try="post_modules/"+ts+"/testsuite")) return ({ try }); +  return ({});   }      // -  + // Plugins + // +  + class WidenerPlugin + { +  inherit Plugin; +  int shift; +  +  int(0..1) active(Test t) +  { +  shift = t->number % 3; +  return !!shift; +  } +  +  string process_name(string name) +  { +  return sprintf("%s (shift %d)", name, shift); +  } +  +  string preprocess(string source) +  { +  string widener = ([ 0:"", +  1:"\nint \x30c6\x30b9\x30c8=0;\n", +  2:"\nint \x10001=0;\n" ])[shift]; +  return source + "\n" + widener; +  } + } +  + class SaveParentPlugin + { +  inherit Plugin; +  +  int(0..1) active(Test t) +  { +  if( has_value(t->source, "don't save parent") ) return 0; +  return 0; // Disabled for now. +  return (t->number/6)&1; +  } +  +  string process_name(string name, string source) +  { +  return name + " (save parent)"; +  } +  +  string preprocess(string source) +  { +  return "#pragma save_parent\n# 1\n" + source; +  } + } +  + class CRNLPlugin + { +  inherit Plugin; +  +  int(0..1) active(Test t) +  { +  return (t->number/3)&1; +  } +  +  string process_name(string name) +  { +  return name + " (CRNL)"; +  } +  +  string preprocess(string source) +  { +  return replace(source, "\n", "\r\n"); +  } + } +  + class LinePlugin + { +  inherit Plugin; +  string preprocess(string source) +  { +  if(source[-1]!='\n') source+="\n"; +  +  int computed_line=sizeof(source/"\n"); +  foreach((source/"#")[1..], string cpp) +  { +  // FIXME: We could calculate the offset from this value. +  if(has_prefix(cpp,"line") || sscanf(cpp,"%*d")) +  { +  computed_line=0; +  break; +  } +  } +  +  return source + +  "int __cpp_line=__LINE__; " +  "int __rtl_line=([array(array(int))]backtrace())[-1][1]; " +  "int __computed_line="+computed_line+";\n"; +  } +  +  int(0..1) inspect(Test t, object o) +  { +  if( o->__cpp_line != o->__rtl_line || +  ( o->__computed_line && o->__computed_line!=o->__cpp_line)) +  { +  log_msg(t->name() + " Line numbering failed.\n"); +  print_code(t->prepare_source()); +  log_msg(" Preprocessed:\n"); +  print_code(cpp(t->prepare_source(), t->file)); +  log_msg(" CPP lines: %d\n",o->__cpp_line); +  log_msg(" RTL lines: %d\n",o->__rtl_line); +  if(o->__computed_line) +  log_msg("Actual lines: %d\n",o->__computed_line); +  return 0; +  } +  return 1; +  } + } +  + //   // Main program   //      int main(int argc, array(string) argv)   { -  int watchdog_pid, subprocess; -  int e, verbose, prompt, successes, errors, t, check, asmdebug; +  int watchdog_pid, subprocess, failed_cond; +  int verbose, prompt, successes, errors, t, check, asmdebug;    int skipped; -  array(string) tests; +     array(string) forked;    int start, fail, mem;    int loop=1;    int end=0x7fffffff;    string extra_info=""; -  int shift; +       #if constant(System.getrlimit)    // Attempt to enable coredumps.    // Many Linux distributions default to having coredumps disabled.    catch {    [ int current, int max ] = System.getrlimit("core");    if ((current != -1) && ((current < max) || (max == -1))) {    // Not unlimited, and less than max.    // Attempt to raise.    System.setrlimit("core", max, max);
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:453: Inside #if constant(_assembler_debug)
   ({"check",Getopt.MAY_HAVE_ARG,({"-c","--check"})}),   #if constant(_assembler_debug)    ({"asm",Getopt.MAY_HAVE_ARG,({"--assembler-debug"})}),   #endif    ({"mem",Getopt.NO_ARG,({"-m","--mem","--memory"})}),    ({"auto",Getopt.MAY_HAVE_ARG,({"-a","--auto"})}),    ({"notty",Getopt.NO_ARG,({"-T","--notty"})}),   #ifdef HAVE_DEBUG    ({"debug",Getopt.MAY_HAVE_ARG,({"-d","--debug"})}),   #endif -  ({"regression",Getopt.NO_ARG,({"-r","--regression"})}), +     ({"subprocess", Getopt.NO_ARG, ({"--subprocess"})}), -  +  ({"cond",Getopt.NO_ARG,({"--failed-cond","--failed-conditionals"})}),    )),array opt)    {    switch(opt[0])    {    case "no-watchdog":    use_watchdog=0;    break;       case "watchdog":    watchdog_pid = (int)opt[1];
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:509:    break;    }    case "loop": loop=foo(opt[1]); break;    case "trace": t+=foo(opt[1]); break;    case "check": check+=foo(opt[1]); break;    case "asm": asmdebug+=foo(opt[1]); break;    case "mem": mem=1; break;       case "auto":    if(stringp(opt[1])) -  testsuites=find_testsuites(opt[1]); +  testsuites+=sort(find_testsuites(opt[1]));    else -  testsuites=find_testsuites("."); +  testsuites+=sort(find_testsuites("."));    break;    -  case "regression": -  add_constant("regression", 1); -  break; -  +     case "subprocess":    subprocess = 1;    break;    -  +  case "cond": +  failed_cond = 1; +  break; +    #ifdef HAVE_DEBUG    case "debug":    {    object p=Stdio.Port();    p->bind(0);    log_msg("Debug port is: %s\n",p->query_address());    sscanf(p->query_address(),"%*s %d",int portno);    extra_info+=sprintf(" dport:%d",portno);    thread_create(lambda(object p){    while(p)
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:551: Inside #if defined(HAVE_DEBUG)
   },p);    }   #endif    }    }       // For easy access in spawned test scripts.    putenv ("TEST_VERBOSITY", (string) verbose);    putenv ("TEST_ON_TTY", (string) (maybe_tty && Stdio.Terminfo.is_tty()));    -  Tools.Testsuite.log_start (verbose, maybe_tty && Stdio.Terminfo.is_tty()); +  log_start (verbose, maybe_tty && Stdio.Terminfo.is_tty());       if (watchdog_pid) {   #if defined(__NT__) && !constant(thread_create)    log_msg("Watchdog not supported on NT without threads.\n");    return EXIT_WATCHDOG_FAILED;   #else    Watchdog (watchdog_pid, verbose);    return -1;   #endif    }
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:588:    // FIXME: end handling is not quite correct.    if (end != 0x7fffffff) forked += ({ "--end-after=" + end });    if (fail) forked += ({ "--fail" });    // forked is handled here.    // loop is handled here.    if (t) forked += ({ "--trace=" + t });    if (check) forked += ({ "--check=" + check });    if (asmdebug) forked += ({ "--asm=" + asmdebug });    if (mem) forked += ({ "--memory" });    // auto already handled. -  if (all_constants()->regression) forked += ({ "--regression" }); +  if (failed_cond) forked += ({ "--failed-cond" });    forked += ({"--subprocess"});    // debug port not propagated.    //log_msg("forked:%O\n", forked);    }       Process.create_process watchdog;    if(use_watchdog)    {    // A subprocess can assume the watchdog is already installed on stdout.    if (!subprocess) {
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:613:    // some reason to make a pipe/socket that the watchdog process can    // do nonblocking on (Linux 2.6/glibc 2.5). Maybe a bug in the new    // epoll stuff? /mast    // No, you had swapped the read and write ends of the pipe. /grubba   #ifdef __NT__    Stdio.File pipe_2 = pipe_1->pipe(Stdio.PROP_IPC);   #else /* !__NT__ */    Stdio.File pipe_2 = pipe_1->pipe(Stdio.PROP_IPC | Stdio.PROP_NONBLOCK);   #endif /* __NT__ */    if (!pipe_2) { -  log_msg ("Failed to create pipe for watchdog: %s\n", +  log_msg ("Failed to create pipe for watchdog: %s.\n",    strerror (pipe_1->errno()));    exit(EXIT_WATCHDOG_FAILED);    }    pipe_2->dup2 (Stdio.stdout);    watchdog=Process.create_process(    backtrace()[0][3] + ({ "--watchdog="+getpid() }),    (["stdin": pipe_1, "stdout": orig_stdout]));    pipe_1->close();    orig_stdout->close();    // Note that the following message gets sent to the watchdog.
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:660:    add_constant("__watchdog_show_last_test", watchdog_show_last_test);    add_constant("__send_watchdog_command", send_watchdog_command);    add_constant("_verbose", verbose);    add_constant ("log_msg", log_msg);    add_constant ("log_msg_cont", log_msg_cont);    add_constant ("log_status", log_status);       if(!subprocess)    log_msg("Begin tests at %s (pid %d)\n", ctime(time())[..<1], getpid());    -  testsuites += Getopt.get_args(argv, 1)[1..]; -  foreach(testsuites; int pos; string ts) { -  testsuites[pos] = ts = find_test(ts); -  if(!file_stat(ts)) +  foreach(Getopt.get_args(argv, 1)[1..], string ts) { +  array(string) tests = find_test(ts); +  if(!sizeof(tests))    exit(EXIT_TEST_NOT_FOUND, "Could not find test %O.\n", ts); -  +  testsuites += tests;    }       if(!sizeof(testsuites))    exit(EXIT_TEST_NOT_FOUND,    "No tests found. Use --help for more information.\n");      #if 1    // Store the name of all constants so that we can see    // if any constant has been leaked from the testsuite.    array const_names = indices(all_constants());
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:689:    _assembler_debug(asmdebug);   #endif       while(loop--)    {    successes=errors=0;    if (forked) {    foreach(testsuites, string testsuite) {    int failure;    array(int) subres = -  Tools.Testsuite.low_run_script (forked + ({ testsuite }), ([])); +  low_run_script (forked + ({ testsuite }), ([]));    if (!subres) { -  +  log_status (""); +  log_msg("Failed to spawn testsuite %O.\n", testsuite);    errors++;    failure = 1;    } else {    [int sub_succeeded, int sub_failed, int sub_skipped] = subres;    if (!(sub_succeeded || sub_failed || sub_skipped))    continue; -  if (verbose) { +  if (verbose || sub_failed) {    log_status ("");    log_msg("Subresult: %d tests, %d failed, %d skipped\n",    sub_succeeded + sub_failed, sub_failed, sub_skipped);    }    successes += sub_succeeded;    errors += sub_failed;    skipped += sub_skipped;    if (sub_failed) failure = 1;    }    if ((verbose > 1) || (fail && errors))    log_msg("Accumulated: %d tests, %d failed, %d skipped\n",    successes + errors, errors, skipped);    if (fail && errors) {    exit(EXIT_TEST_FAILED);    }    }    } else {    testloop:    foreach(testsuites, string testsuite)    { -  [string pike_compat, tests] = read_tests( testsuite ); -  -  if (!sizeof (tests)) +  Testsuite tests = read_tests( testsuite ); +  if (!objectp(tests) || !sizeof(tests))    continue;    -  log_msg("Doing tests in %s%s (%s)\n", testsuite, -  pike_compat ? " in " + pike_compat + " compat mode" : "", +  log_msg("Doing tests in %s (%s)\n", +  tests->name ? tests->name() : testsuite,    ({sizeof(tests) + " tests",    subprocess && ("pid " + getpid())}) * ", ");    int qmade, qskipped, qmadep, qskipp;    -  int testno, testline; -  for(e=start;e<sizeof(tests);e++) +  tests+=start; +  foreach(tests; int e; Test test)    {    if (!((e-start) % 10))    report_size();       int skip=0, prev_errors = errors;    object o;    mixed a,b;       // Extra consistency checks?    if(check)    {    if(check>0 || (e % -check)==0 )    _verify_internals();    }    if(check>3) {    gc();    _verify_internals();    }    -  string test = tests[e]; -  +     // Is there a condition for this test? -  string condition; -  if( sscanf(test, "COND %s\n%s", condition, test)==2 ) +  if( sizeof(test->conditions) )    { -  +  // FIXME: Support more than one condition (current testsuite +  // format only handles one though) +  if( sizeof(test->conditions)>1 ) +  error("Only one concurrent condition supported.\n"); +     int tmp; -  +  string condition = test->conditions[0];    if(!(tmp=cond_cache[condition]))    {    mixed err = catch { -  tmp=!!(compile_string("mixed c() { return "+condition+"; }", -  "Cond "+(e+1))()->c()); +  tmp=!!(test->compile("mixed c() { return "+condition+"; }")()->c());    };       if(err) {    if (err && err->is_cpp_or_compilation_error) -  log_msg( "Conditional %d%s failed.\n", -  e+1, testline?" (line "+testline+")":""); +  log_msg( "Conditional %d failed.\n", e+1);    else -  log_msg( "Conditional %d%s failed:\n" -  "%s\n", e+1, testline?" (line "+testline+")":"", +  log_msg( "Conditional %d failed:\n%s\n", e+1,    describe_backtrace(err) );    print_code( condition );    errors++;    tmp = -1;    }    -  +  if (tmp != 1) { +  if ((verbose > 1 || failed_cond) && !err) { +  log_msg("Conditional %d failed:\n", e+1); +  print_code( condition ); +  } +  } else if (verbose > 5) { +  log_msg("Conditional %d succeeded.\n", e+1); +  if (verbose > 9) { +  print_code( condition ); +  } +  } +     if(!tmp) tmp=-1;    cond_cache[condition]=tmp;    }       if(tmp==-1)    {    if(verbose>1)    log_msg("Not doing test "+(e+1)+"\n");    successes++;    skipped++;    skip=1;    }    }    -  string|int type; -  sscanf(test, "%s\n%s", type, test); +  string source = test->source;    -  string testfile; -  sscanf(type, "%s: test %d, expected result: %s", testfile, testno, type); +  watchdog_start_new_test ("Test %d at %s:%d", e + 1, +  test->file, test->line);    -  if (testfile) { -  array split = testfile / ":"; -  testline = (int) split[-1]; -  testfile = split[..sizeof (split) - 2] * ":"; -  } -  -  watchdog_start_new_test ("Test %d at %s:%d", e + 1, testfile, testline); -  +     if(maybe_tty && Stdio.Terminfo.is_tty())    {    if(verbose == 1) {    // \r isn't necessary here if everyone uses    // Tools.Testsuite.{log_msg|log_status}, but it avoids    // messy lines for all the tests that just write directly. -  log_status ("test %d, line %d\r", e+1, testline); +  log_status ("test %d, line %d\r", e+1, test->line);    }    }    else if(verbose > 1){    if(skip) {    if(qmade)    log_msg("Made %d test%s.\n", qmade, qmade==1?"":"s");    qmade=0;    qskipp=1;    qskipped++;    }
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:857:    case 39:    log_msg_cont(skip?"- ":"+ ");    break;       case 49:    log_msg_cont(skip?"-\n":"+\n");    }    }    if(skip) continue;    -  if (!testfile || !testno || !type) { -  log_msg ("Invalid format in test file: %O\n", type); -  errors++; -  continue; -  } +  test->add_plugin( WidenerPlugin() ); +  test->add_plugin( SaveParentPlugin() ); +  test->add_plugin( CRNLPlugin() ); +  test->add_plugin( LinePlugin() );    -  if (pike_compat) -  test = "#pike " + pike_compat + "\n" + test; -  +     if (prompt) {    if (Stdio.Readline()->    read(sprintf("About to run test: %d. [<RETURN>/'quit']: ", -  testno)) == "quit") { +  test->number)) == "quit") {    break testloop;    }    }       if(verbose>1)    { -  log_msg("Doing test %d (%d total) at %s:%d%s\n", -  testno, successes+errors+1, testfile, testline, extra_info); -  if(verbose>2) print_code(test); +  log_msg("Doing test %d (%d total) at %s:%d%s\n", test->number, +  successes+errors+1, test->file, test->line, extra_info); +  if(verbose>2) print_code(source);    }       if(check > 1) _verify_internals();    -  shift++; -  string fname = testfile + ":" + testline + ": Test " + testno + -  " (shift " + (shift%3) + ")"; +  string fname = test->name();    -  string widener = ([ 0:"", -  1:"\nint \x30c6\x30b9\x30c8=0;\n", -  2:"\nint \x10001=0;\n" ])[shift%3]; -  -  // widener += "#pragma strict_types\n"; -  -  if(test[-1]!='\n') test+="\n"; -  -  int computed_line=sizeof(test/"\n"); -  array gnapp= test/"#"; -  for(int e=1;e<sizeof(gnapp);e++) +  if(verbose>9) print_code(test->prepare_source()); +  switch(test->type)    { -  if(sscanf(gnapp[e],"%*d")) -  { -  computed_line=0; -  break; -  } -  } -  string linetester="int __cpp_line=__LINE__; int __rtl_line=([array(array(int))]backtrace())[-1][1];\n"; -  -  string to_compile = test + linetester + widener; -  -  if((shift/6)&1) -  { -  if(search("don't save parent",to_compile) != -1) -  { -  fname+=" (save parent)"; -  to_compile= -  "#pragma save_parent\n" -  "# 1\n" -  +to_compile; -  } -  } -  -  if((shift/3)&1) -  { -  fname+=" (CRNL)"; -  to_compile=replace(to_compile,"\n","\r\n"); -  } -  -  // _optimizer_debug(5); -  -  if(verbose>9) print_code(to_compile); +     WarningFlag wf; -  switch(type) -  { +     mixed at,bt;    mixed err;    case "COMPILE":    wf = WarningFlag(); -  master()->set_inhibit_compile_errors(wf); -  _dmalloc_set_name(fname,0); -  if(mixed err = catch(compile_string(to_compile, testsuite))) +  test->inhibit_errors = wf; +  test->compile(); +  if(test->compilation_error)    { -  _dmalloc_set_name(); -  master()->set_inhibit_compile_errors(0); -  if (objectp (err) && err->is_cpp_or_compilation_error) +  if (test->compilation_error->is_cpp_or_compilation_error)    log_msg ("%s failed.\n", fname);    else -  log_msg ("%s failed:\n%s", fname, describe_backtrace (err)); -  print_code(test); +  log_msg ("%s failed:\n%s", fname, +  describe_backtrace (test->compilation_error)); +  print_code(source);    errors++;    } -  else { -  _dmalloc_set_name(); -  master()->set_inhibit_compile_errors(0); -  +  else +  {    if(wf->warning) { -  log_msg (fname + " produced warning.\n"); -  log_msg ("%{%s\n%}", wf->warnings); -  print_code(test); +  wf->write_warnings(fname, source);    errors++;    break;    }       successes++;    }    break;       case "COMPILE_ERROR": -  master()->set_inhibit_compile_errors(1); -  _dmalloc_set_name(fname,0); -  if(mixed err = catch(compile_string(to_compile, testsuite))) +  test->compile(); +  if(test->compilation_error)    { -  if (objectp (err) && err->is_cpp_or_compilation_error) { -  _dmalloc_set_name(); +  if (test->compilation_error->is_cpp_or_compilation_error) {    successes++;    }    else { -  _dmalloc_set_name(); +     log_msg ("%s failed.\n"    "Expected compile error, got another kind of error:\n%s", -  fname, describe_backtrace (err)); -  print_code(test); +  fname, describe_backtrace (test->compilation_error)); +  print_code(source);    errors++;    }    }    else { -  _dmalloc_set_name(); +     log_msg (fname + " failed (expected compile error).\n"); -  print_code(test); +  print_code(source);    errors++;    } -  master()->set_inhibit_compile_errors(0); +     break;       case "COMPILE_WARNING":    wf = WarningFlag(); -  master()->set_inhibit_compile_errors(wf); -  _dmalloc_set_name(fname,0); -  if(mixed err = catch(compile_string(to_compile, testsuite))) +  test->inhibit_errors = wf; +  test->compile(); +  if(test->compilation_error)    { -  _dmalloc_set_name(); -  if (objectp (err) && err->is_cpp_or_compilation_error) +  if (test->compilation_error->is_cpp_or_compilation_error)    log_msg ("%s failed.\n", fname);    else -  log_msg ("%s failed:\n%s", fname, describe_backtrace (err)); -  print_code(test); +  log_msg ("%s failed:\n%s", fname, +  describe_backtrace (test->compilation_error)); +  print_code(source);    errors++;    }    else { -  _dmalloc_set_name(); +     if( wf->warning )    successes++;    else {    log_msg(fname + " failed (expected compile warning).\n"); -  print_code(test); +  print_code(source);    errors++;    }    } -  master()->set_inhibit_compile_errors(0); +     break;       case "EVAL_ERROR": -  master()->set_inhibit_compile_errors(1); -  _dmalloc_set_name(fname,0); -  +     at = gauge {    err=catch {    // Is it intentional that compilation errors are    // considered success too? /mast    // Yes, apparently it is. There are tests that don't    // care whether the error is caught during compilation    // or evaluation. /mast -  a = compile_string(to_compile, testsuite)()->a(); +  a = test->compile()()->a();    };    };    if(err)    { -  _dmalloc_set_name(); +     successes++;    if(verbose>3)    log_msg("Time in a(): %f\n",at);    }    else {    watchdog_show_last_test(); -  _dmalloc_set_name(); +     log_msg("%s failed (expected eval error).\n"    "Got %O\n", fname, a); -  print_code(test); +  print_code(source);    errors++;    } -  master()->set_inhibit_compile_errors(0); +     break;       default:    if (err = catch{    wf = WarningFlag(); -  master()->set_inhibit_compile_errors(wf); -  _dmalloc_set_name(fname,0); -  o=compile_string(to_compile,testsuite)(); -  _dmalloc_set_name(); +  test->inhibit_errors = wf; +  o=test->compile()(); +  if(test->compilation_error) +  throw(test->compilation_error);       if(check > 1) _verify_internals();       a=b=0;    if(t) trace(t); -  _dmalloc_set_name(fname,1); +     if(functionp(o->a))    {    // trace(10);    at = gauge { a=o->a(); };    // trace(0);    }       if(functionp(o->b))    {    bt = gauge { b=o->b(); };    }    -  _dmalloc_set_name(); -  +     if(t) trace(0);    if(check > 1) _verify_internals();       if(wf->warning) { -  log_msg("%s produced warning.\n" -  "%{%s\n%}", fname, wf->warnings); -  print_code(test); +  wf->write_warnings(fname, source);    errors++;    break;    } -  master()->set_inhibit_compile_errors(0); -  +     }) {    if(t) trace(0); -  master()->set_inhibit_compile_errors(0); +     watchdog_show_last_test(); -  if (objectp (err) && err->is_cpp_or_compilation_error) +  if (test->compilation_error?->is_cpp_or_compilation_error)    log_msg ("%s failed.\n", fname);    else -  log_msg ("%s failed:\n%s\n", fname, describe_backtrace (err)); -  print_code(test); +  log_msg ("%s failed:\n%s\n", fname, +  describe_backtrace (test->compilation_error||err)); +  print_code(source);    errors++;    break;    }    -  if( o->__cpp_line != o->__rtl_line || -  ( computed_line && computed_line!=o->__cpp_line)) -  { -  log_msg(fname + " Line numbering failed.\n"); -  print_code(to_compile); -  log_msg(" Preprocessed:\n"); -  print_code(cpp(to_compile, testsuite)); -  log_msg(" CPP lines: %d\n",o->__cpp_line); -  log_msg(" RTL lines: %d\n",o->__rtl_line); -  if(computed_line) -  log_msg("Actual lines: %d\n",computed_line); +  foreach(test->plugins;; Plugin plugin) +  if( plugin->inspect && !plugin->inspect(test, o) )    errors++; -  } +        if(verbose>2)    log_msg("Time in a(): %f, Time in b(): %O\n",at,bt);    -  switch(type) +  switch(test->type)    {    case "FALSE":    if(a)    {    watchdog_show_last_test();    log_msg(fname + " failed.\n"); -  print_code(test); -  log_msg("o->a(): %O\n",a); +  print_code(source); +  log_msg_result("o->a(): %O\n",a);    errors++;    }    else {    successes++;    }    break;       case "TRUE":    if(!a)    {    watchdog_show_last_test();    log_msg(fname + " failed.\n"); -  print_code(test); -  log_msg("o->a(): %O\n",a); +  print_code(source); +  log_msg_result("o->a(): %O\n",a);    errors++;    }    else {    successes++;    }    break;       case "PUSH_WARNING":    if (!stringp(a)) {    watchdog_show_last_test();    log_msg(fname + " failed.\n"); -  print_code(test); -  log_msg("o->a(): %O\n", a); +  print_code(source); +  log_msg_result("o->a(): %O\n", a);    } else {    pushed_warnings[a]++;    }    break;       case "POP_WARNING":    if (!stringp(a)) {    watchdog_show_last_test();    log_msg(fname + " failed.\n"); -  print_code(test); -  log_msg("o->a(): %O\n", a); +  print_code(source); +  log_msg_result("o->a(): %O\n", a);    } else if (pushed_warnings[a]) {    if (!--pushed_warnings[a]) {    m_delete(pushed_warnings, a);    }    } else {    watchdog_show_last_test();    log_msg(fname + " failed.\n"); -  print_code(test); -  log_msg("o->a(): %O not pushed!\n", a); +  print_code(source); +  log_msg_result("o->a(): %O not pushed!\n", a);    }    break;       case "RUN":    successes++;    break;       case "RUNCT":    if(!a || !arrayp(a) ||    sizeof(a) < 2 || !intp(a[0]) || !intp(a[1]) ||    (sizeof (a) == 3 && !intp (a[2])) ||    sizeof (a) > 3) {    watchdog_show_last_test();    log_msg(fname + " failed to return proper results.\n"); -  print_code(test); -  log_msg("o->a(): %O\n",a); +  print_code(source); +  log_msg_result("o->a(): %O\n",a);    errors++;    }    else {    successes += a[0];    errors += a[1];    if (sizeof (a) >= 3) skipped += a[2]; -  if (verbose>1) +  if ((verbose>1) || a[1])    if(a[1])    log_msg("%d/%d tests failed%s.\n",    a[1], a[0]+a[1],    sizeof (a) >= 3 ? " (skipped " + a[2] + ")" : "");    else    log_msg("Did %d tests in %s%s.\n", a[0], fname,    sizeof (a) >= 3 ? " (skipped " + a[2] + ")" : "");    }    break;       case "EQ": -  if(a!=b) +  if(a==b)    { -  +  successes++; +  } +  else {    watchdog_show_last_test();    log_msg(fname + " failed.\n"); -  print_code(test); -  log_msg("o->a(): %O\n" +  print_code(source); +  log_msg_result("o->a(): %O\n"    "o->b(): %O\n", a, b);    errors++;    if (stringp(a) && stringp(b) && (sizeof(a) == sizeof(b)) &&    (sizeof(a) > 20)) {    log_msg("Differences at:\n");    int i;    for(i = 0; i < sizeof(a); i++) {    if (a[i] != b[i]) {    log_msg(" %4d: 0x%04x != 0x%04x\n", i, a[i], b[i]);    }    }    }   #if 0 && constant(_dump_program_tables)    _dump_program_tables(object_program(o));   #endif    } -  else { -  successes++; -  } +     break;       case "EQUAL": -  if(!equal(a,b)) +  if(equal(a,b))    { -  +  successes++; +  } +  else {    watchdog_show_last_test();    log_msg(fname + " failed.\n"); -  print_code(test); -  log_msg("o->a(): %O\n" +  print_code(source); +  log_msg_result("o->a(): %O\n"    "o->b(): %O\n", a, b);    errors++;    if (stringp(a) && stringp(b) && (sizeof(a) == sizeof(b)) &&    (sizeof(a) > 20)) {    log_msg("Differences at:\n");    int i;    for(i = 0; i < sizeof(a); i++) {    if (a[i] != b[i]) {    log_msg(" %4d: 0x%04x != 0x%04x\n", i, a[i], b[i]);    }    }    }    } -  else { -  successes++; -  } +     break;       default: -  log_msg("%s: Unknown test type (%O).\n", fname, type); +  log_msg("%s: Unknown test type (%O).\n", fname, test->type);    errors++;    }    }       if(check > 2) _verify_internals();       if(fail && errors)    exit(EXIT_TEST_FAILED);       if(successes+errors > end)
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:1303:    }    else if (verbose) {    log_msg("\n");    }    }    }    report_size();    if(mem)    {    int total; -  tests=0; +     gc();    mapping tmp=_memory_usage();    log_msg("%-10s: %6s %10s\n","Category","num","bytes");    foreach(sort(indices(tmp)),string foo)    {    if(sscanf(foo,"%s_bytes",foo))    {    log_msg("%-10s: %6d %10d\n",    foo+"s",    tmp["num_"+foo+"s"],
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:1328:    log_msg( "%-10s: %6s %10d\n",    "Total", "", total );    }    }       if (!subprocess) {    log_status ("");       if(errors || verbose>1)    { -  log_msg("Failed tests: "+errors+".\n"); +  log_msg("Failed tests: "+errors+". \n");    }       log_msg("Total tests: %d (%d tests skipped)\n", successes+errors, skipped);    if(verbose)    log_msg("Finished tests at "+ctime(time()));    }    else {    // Clear the output buffer in the watchdog so that    // Tools.Testsuite.low_run_script doesn't print it when errors is    // nonzero. That has instead been handled above for each failing    // test.    watchdog_start_new_test ("");    -  Tools.Testsuite.report_result (successes, errors, skipped); +  report_result (successes, errors, skipped);    }      #if 1    if(verbose && sizeof(all_constants())!=sizeof(const_names)) {    multiset const_names = (multiset)const_names; -  foreach(indices(all_constants()), string const) -  if( !const_names[const] ) -  log_msg("Leaked constant %O\n", const); +  foreach(indices(all_constants()), string const_name) +  if( !const_names[const_name] ) +  log_msg("Leaked constant %O\n", const_name);    }   #endif    -  add_constant("regression"); +     add_constant("_verbose");    add_constant("__signal_watchdog");    add_constant("RUNPIKE");       if(watchdog)    {    Stdio.stdout->close();    watchdog->wait();    }   
pike.git/lib/modules/Tools.pmod/Standalone.pmod/test_pike.pike:1412:    2 _verify_internals is run after every compilation.    3 _verify_internals is run after every test.    4 An extra gc and _verify_internals is run before    every test.    X<0 For values below zero, _verify_internals will be run    before every n:th test, where n=abs(X).   -m, --mem, --memory Print out memory allocations after the tests.   -a, --auto[=dir] Let the test program find the testsuites automatically.   -T, --notty Format output for non-tty.   -d, --debug Opens a debug port. + --failed-cond Outputs failing test conditionals.   ";