text: #!/usr/bin/env python3
  
  import ctypes
  import random
  import gmpapi
  import wrappers
  import glob
  import sys
  import os
  from optparse import OptionParser
  from gmpapi import void
  from gmpapi import ilong
  from gmpapi import ulong
  from gmpapi import mpz_t
  from gmpapi import voidp
  from gmpapi import size_t
  from gmpapi import size_tp
  from gmpapi import iint
  from gmpapi import charp
  from gmpapi import mpq_t
  
  def print_failure(line, test):
    print("FAIL: {}@{}".format(line,test))
  
  
  def run_tests(test_file, options):
    passes = 0
    failures = 0
    fail_lines = []
    for (line, test) in enumerate(open(test_file), start=1):
      if test.startswith("#"):
        continue
      if options.skip > 0 and line < options.skip:
        continue
      name,args = test.split("|")
      if options.verbose or (options.progress > 0 and line % options.progress == 0):
        print("TEST: {}@{}".format(line, test), end="")
      api = gmpapi.get_api(name)
      wrapper = wrappers.get_wrapper(name)
      input_args = args.split(",")
      if len(api.params) != len(input_args):
        raise RuntimeError("Mismatch in args length: {} != {}".format(len(api.params), len(input_args)))
  
      call_args = []
      for i in range(len(api.params)):
        param = api.params[i]
        if param == mpz_t:
          call_args.append(bytes(input_args[i],"utf-8"))
        elif param == mpq_t:
          call_args.append(bytes(input_args[i],"utf-8"))
        elif param == ulong:
          call_args.append(ctypes.c_ulong(int(input_args[i])))
        elif param == ilong:
          call_args.append(ctypes.c_long(int(input_args[i])))
        elif param == voidp or param == size_tp:
          call_args.append(ctypes.c_void_p(None))
        elif param == size_t:
          call_args.append(ctypes.c_size_t(int(input_args[i])))
        elif param == iint:
          call_args.append(ctypes.c_int(int(input_args[i])))
        # pass null for charp
        elif param == charp:
          if input_args[i] == "NULL":
            call_args.append(ctypes.c_void_p(None))
          else:
            call_args.append(bytes(input_args[i],"utf-8"))
        else:
          raise RuntimeError("Unknown param type: {}".format(param))
  
      res = wrappers.run_test(wrapper, line, name, gmp_test_so, imath_test_so, *call_args)
      if not res:
        failures += 1
        print_failure(line,test)
        fail_lines.append((line,test))
      else:
        passes += 1
    return (passes,failures, fail_lines)
  
  def parse_args():
    parser = OptionParser()
    parser.add_option("-f", "--fork", help="fork() before each operation",
                      action="store_true", default=False)
    parser.add_option("-v", "--verbose", help="print PASS and FAIL tests",
                      action="store_true", default=False)
    parser.add_option("-p", "--progress", help="print progress every N tests ",
                      metavar="N", type="int", default=0)
    parser.add_option("-s", "--skip", help="skip to test N",
                      metavar="N", type="int", default=0)
    return parser.parse_args()
  
  if __name__ == "__main__":
    (options, tests) = parse_args()
    gmp_test_so = ctypes.cdll.LoadLibrary("gmp_test.so")
    imath_test_so = ctypes.cdll.LoadLibrary("imath_test.so")
  
    wrappers.verbose = options.verbose
    wrappers.fork    = options.fork
  
    total_pass = 0
    total_fail = 0
    all_fail_lines = []
    for test_file in tests:
      print("Running tests in {}".format(test_file))
      (passes,failures,fail_lines) = run_tests(test_file, options)
      print("  Tests: {}. Passes: {}. Failures: {}.".format(passes+failures, passes, failures))
      total_pass += passes
      total_fail += failures
      all_fail_lines += fail_lines
  
    print("="*70)
    print("Total")
    print("  Tests: {}. Passes: {}. Failures: {}.".format(total_pass+total_fail, total_pass, total_fail))
    if len(all_fail_lines) > 0:
      print("Failing Tests:")
      for (line, test) in all_fail_lines:
        print(test.rstrip())
  
  