#!/usr/bin/env python

import gmpapi
import sys


def print_header(outf):
    outf.write(
        """
#AUTOGENERATED FILE
import ctypes
import os
import sys
import binascii

verbose = False
fork    = False
  """
    )


def print_cmp(outf):
    outf.write(
        """
def passt(line, name, a_s, b_s):
    if verbose:
      print("PASS: {}@{} {} == {}".format(line, name, a_s, b_s))
    return True

def fail(line, name, a_s, b_s):
    print("FAIL: {}@{} {} != {}".format(line, name, a_s,b_s))
    return False

def cstr_eq(line, name, a, b):
  a_s = a.value.decode("utf-8")
  b_s = b.value.decode("utf-8")

  if a_s == b_s:
    return passt(line, name, a_s, b_s)
  else:
    return fail(line, name, a_s, b_s)

def bytes_eq(line, name, a, b):
  if a == b:
    return passt(line, name, a, b)
  else:
    return fail(line, name, a, b)

def run_test(test, line, name, gmp_test_so, imath_test_so, *args):
  if fork:
    childpid = os.fork()
  else:
    childpid = 0
  if childpid == 0:
    eq = test(line, name, gmp_test_so, imath_test_so, *args)
    if fork:
      sys.exit(eq != True)
    else:
      return eq
  else:
    (pid, status) = os.waitpid(childpid, 0)
    return status == 0

# custom tests
def test_mpz_export(line, name, gmp_test_so, imath_test_so, *args):
  # do not use first two args from the test. need to create our own pointers
  used_args = args[2:]
  gbuf  = ctypes.create_string_buffer(b'0xdeadbeef'*1024);
  gsize = ctypes.c_size_t()
  gout  = ctypes.c_void_p()
  ibuf  = ctypes.create_string_buffer(b'0xdeadbeef'*1024);
  isize = ctypes.c_size_t()
  iout  = ctypes.c_void_p()
  word_size = args[3].value

  #Test with a NULL pointer
  gmp_test_so.test_mpz_export(ctypes.byref(gout), None, ctypes.byref(gsize), *used_args)
  imath_test_so.test_mpz_export(ctypes.byref(iout), None, ctypes.byref(isize), *used_args)
  gb = ctypes.string_at(gout.value, gsize.value * word_size)
  ib = ctypes.string_at(iout.value, isize.value * word_size)
  if not bytes_eq(line, name, gb, ib):
    return False

  #Test with a provided buffer
  gmp_test_so.test_mpz_export(ctypes.byref(gout), gbuf, ctypes.byref(gsize), *used_args)
  imath_test_so.test_mpz_export(ctypes.byref(iout), ibuf, ctypes.byref(isize), *used_args)
  #print("G:gbuf", gbuf.raw[:gsize.value * word_size])
  #print("I:ibuf", ibuf.raw[:isize.value * word_size])
  gb = ctypes.string_at(gout.value, gsize.value * word_size)
  ib = ctypes.string_at(iout.value, isize.value * word_size)
  if not bytes_eq(line, name, gb, ib):
    return False

  return True

def test_mpz_import(line, name, gmp_test_so, imath_test_so, *args):
  # do not use first two args from the test. need to create our own pointers
  gout  = ctypes.create_string_buffer(b'0xdeadbeef'*1024);
  iout  = ctypes.create_string_buffer(b'0xdeadbeef'*1024);

  gmp_test_so.test_mpz_import(gout, *args)
  imath_test_so.test_mpz_import(iout, *args)
  #print(gout.raw[:70])
  #print(iout.raw[:70])
  return cstr_eq(line, name, gout, iout)

"""
    )


def print_api(name, outf):
    outf.write(
        """
def test_{0}(line, name, gmp_test_so, imath_test_so, *args):
  gout = ctypes.create_string_buffer(1024*4);
  iout = ctypes.create_string_buffer(1024*4);
  gmp_test_so.test_{0}(gout, *args)
  imath_test_so.test_{0}(iout, *args)
  eq = cstr_eq(line, name, gout, iout)
  return eq
""".format(
            name
        )
    )


def print_api_map(outf):
    outf.write(
        """
def get_wrapper(name):
  test_wrappers = {
"""
    )
    for api in gmpapi.apis:
        outf.write('    "{}" : {},\n'.format(api.name, "test_" + api.name))
    outf.write("  }\n")
    outf.write("  return test_wrappers[name]\n")


if __name__ == "__main__":
    outf = sys.stdout
    print_header(outf)
    print_cmp(outf)
    for api in gmpapi.apis:
        if not api.custom_test:
            print_api(api.name, outf)
    print_api_map(outf)
