| #!/usr/bin/env python |
| import random |
| import gmpapi |
| |
| MAX_SLONG = "9223372036854775807" |
| MIN_SLONG = "-9223372036854775808" |
| MAX_ULONG = "18446744073709551615" |
| MAX_SINT = "2147483647" |
| MIN_SINT = "-2147483648" |
| MAX_UINT = "4294967295" |
| MAX_SSHORT = "32767" |
| MIN_SSHORT = "-32768" |
| MAX_USHORT = "65535" |
| |
| |
| def plus1(x): |
| return str(int(x) + 1) |
| |
| |
| def minus1(x): |
| return str(int(x) - 1) |
| |
| |
| def apply(fun, lst): |
| return list(map(str, map(fun, lst))) |
| |
| |
| mzero_one = ["-0", "-1"] |
| zero_one = ["0", "1"] |
| mm_slong = [MAX_SLONG, MIN_SLONG] |
| mm_slong1 = [minus1(MAX_SLONG), plus1(MIN_SLONG)] |
| mm_ulong = [MAX_ULONG] |
| mm_ulong1 = [minus1(MAX_ULONG)] |
| mm_sint = [MAX_SINT, MIN_SINT] |
| mm_sint1 = [minus1(MAX_SINT), plus1(MIN_SINT)] |
| mm_uint = [MAX_UINT] |
| mm_uint1 = [minus1(MAX_UINT)] |
| mm_sshort = [MAX_SSHORT, MIN_SSHORT] |
| mm_sshort1 = [minus1(MAX_SSHORT), plus1(MIN_SSHORT)] |
| mm_ushort = [MAX_USHORT] |
| mm_ushort1 = [minus1(MAX_USHORT)] |
| mm_all = mm_slong + mm_ulong + mm_sint + mm_uint + mm_sshort + mm_ushort |
| zero_one_all = mzero_one + zero_one |
| |
| mpz_std_list = zero_one_all + mm_all + apply(plus1, mm_all) + apply( |
| minus1, mm_all) |
| si_std_list = zero_one + mm_slong + mm_sint + mm_sshort + mm_slong1 + mm_sint1 + mm_sshort1 |
| ui_std_list = zero_one + mm_ulong + mm_uint + mm_ushort + mm_ulong1 + mm_uint1 + mm_ushort1 |
| |
| |
| def gen_random_mpz(mindigits=1, maxdigits=100, allowneg=True): |
| sign = random.choice(["", "-"]) |
| if not allowneg: |
| sign = "" |
| return sign + gen_digits(random.randint(mindigits, maxdigits)) |
| |
| |
| def gen_random_si(): |
| si = gen_random_mpz(mindigits=1, maxdigits=19) |
| while int(si) > int(MAX_SLONG) or int(si) < int(MIN_SLONG): |
| si = gen_random_mpz(mindigits=1, maxdigits=19) |
| return si |
| |
| |
| def gen_random_ui(): |
| ui = gen_random_mpz(mindigits=1, maxdigits=20, allowneg=False) |
| while int(ui) > int(MAX_ULONG): |
| ui = gen_random_mpz(mindigits=1, maxdigits=20, allowneg=False) |
| return ui |
| |
| |
| def gen_digits(length): |
| if length == 1: |
| i = random.randint(1, 9) |
| else: |
| digits = [random.randint(1, 9) |
| ] + [random.randint(0, 9) for x in range(length - 1)] |
| digits = map(str, digits) |
| i = "".join(digits) |
| return str(i) |
| |
| |
| def gen_mpzs(mindigits=1, maxdigits=100, count=10): |
| return [ |
| gen_random_mpz(mindigits=mindigits, maxdigits=maxdigits) |
| for x in range(count) |
| ] |
| |
| |
| default_count = 10 |
| |
| |
| def gen_sis(count=default_count): |
| return [gen_random_si() for x in range(count)] |
| |
| |
| def gen_uis(count=default_count): |
| return [gen_random_ui() for x in range(count)] |
| |
| |
| def gen_small_mpzs(count=default_count): |
| return gen_mpzs(mindigits=1, maxdigits=4, count=count) |
| |
| |
| def is_small_mpz(s): |
| return len(s) >= 1 and len(s) <= 4 |
| |
| |
| def gen_medium_mpzs(count=default_count): |
| return gen_mpzs(mindigits=5, maxdigits=20, count=count) |
| |
| |
| def is_medium_mpz(s): |
| return len(s) >= 5 and len(s) <= 20 |
| |
| |
| def gen_large_mpzs(count=default_count): |
| return gen_mpzs(mindigits=21, maxdigits=100, count=count) |
| |
| |
| def is_large_mpz(s): |
| return len(s) >= 21 |
| |
| |
| def gen_mpz_spread(count=default_count): |
| return gen_small_mpzs(count) + gen_medium_mpzs(count) + gen_large_mpzs( |
| count) |
| |
| |
| def gen_mpz_args(count=default_count): |
| return mpz_std_list + gen_mpz_spread(count) |
| |
| |
| def gen_mpq_args(count=4): |
| nums = zero_one + gen_mpz_spread(count) |
| dens = ["1"] + gen_mpz_spread(count) |
| return [n + "/" + d for n in nums for d in dens if int(d) != 0] |
| |
| |
| def gen_si_args(): |
| return si_std_list + gen_sis() |
| |
| |
| def gen_ui_args(): |
| return ui_std_list + gen_uis() |
| |
| |
| def gen_list_for_type(t, is_write_only): |
| if (t == gmpapi.mpz_t or t == gmpapi.mpq_t) and is_write_only: |
| return ["0"] |
| elif t == gmpapi.mpz_t: |
| return gen_mpz_args() |
| elif t == gmpapi.ilong: |
| return gen_si_args() |
| elif t == gmpapi.ulong: |
| return gen_ui_args() |
| elif t == gmpapi.mpq_t: |
| return gen_mpq_args() |
| else: |
| raise RuntimeError("Unknown type: {}".format(t)) |
| |
| |
| def gen_args(api): |
| if api.custom_test or api.name in custom: |
| return custom[api.name](api) |
| types = api.params |
| if len(types) == 1: |
| return [[a] for a in gen_list_for_type(types[0], api.is_write_only(0))] |
| elif len(types) == 2: |
| t1 = gen_list_for_type(types[0], api.is_write_only(0)) |
| t2 = gen_list_for_type(types[1], api.is_write_only(1)) |
| return [(a, b) for a in t1 for b in t2] |
| elif len(types) == 3: |
| t1 = gen_list_for_type(types[0], api.is_write_only(0)) |
| t2 = gen_list_for_type(types[1], api.is_write_only(1)) |
| t3 = gen_list_for_type(types[2], api.is_write_only(2)) |
| return [(a, b, c) for a in t1 for b in t2 for c in t3] |
| elif len(types) == 4: |
| t1 = gen_list_for_type(types[0], api.is_write_only(0)) |
| t2 = gen_list_for_type(types[1], api.is_write_only(1)) |
| t3 = gen_list_for_type(types[2], api.is_write_only(2)) |
| t4 = gen_list_for_type(types[3], api.is_write_only(3)) |
| return [(a, b, c, d) for a in t1 for b in t2 for c in t3 for d in t4] |
| else: |
| raise RuntimeError("Too many args: {}".format(len(types))) |
| |
| |
| ################################################################### |
| # |
| # Fixup and massage random data for better test coverage |
| # |
| ################################################################### |
| def mul_mpzs(a, b): |
| return str(int(a) * int(b)) |
| |
| |
| def mpz_divexact_data(args): |
| # set n = n * d |
| divisible = mul_mpzs(args[1], (args[2])) |
| return [(args[0], divisible, args[2])] |
| |
| |
| def mpz_divisible_p_data(args): |
| (n, d) = get_div_data(args[0], args[1], rate=1.0) |
| return [(n, d), (args[0], args[1])] |
| |
| |
| def mpz_div3_data(args): |
| q = args[0] |
| (n, d) = get_div_data(args[1], args[2], rate=1.0) |
| return [(q, n, d), (q, args[1], args[2])] |
| |
| |
| def mpz_pow_data(args, alwaysallowbase1=True): |
| base = int(args[1]) |
| exp = int(args[2]) |
| # allow special numbers |
| if base == 0 or exp == 0 or exp == 1: |
| return [args] |
| if base == 1 and alwaysallowbase1: |
| return [args] |
| |
| # disallow too big numbers |
| if base > 1000 or base < -1000: |
| base = gen_random_mpz(maxdigits=3) |
| if exp > 1000: |
| exp = gen_random_mpz(maxdigits=3, allowneg=False) |
| |
| return [(args[0], str(base), str(exp))] |
| |
| |
| def mpz_mul_2exp_data(args): |
| return mpz_pow_data(args, alwaysallowbase1=False) |
| |
| |
| def mpz_gcd_data(args): |
| r = args[0] |
| a = args[1] |
| b = args[2] |
| s_ = gen_small_mpzs(1)[0] |
| m_ = gen_medium_mpzs(1)[0] |
| l_ = gen_large_mpzs(1)[0] |
| |
| return [ |
| (r, a, b), |
| (r, mul_mpzs(a, b), b), |
| (r, mul_mpzs(a, s_), mul_mpzs(b, s_)), |
| (r, mul_mpzs(a, m_), mul_mpzs(b, m_)), |
| (r, mul_mpzs(a, l_), mul_mpzs(b, l_)), |
| ] |
| |
| |
| def mpz_export_data(api): |
| rop = ["0"] |
| countp = ["0"] |
| order = ["-1", "1"] |
| size = ["1", "2", "4", "8"] |
| endian = ["0"] |
| nails = ["0"] |
| ops = gen_mpz_args(1000) + gen_mpzs( |
| count=100, mindigits=100, maxdigits=1000) |
| |
| args = [] |
| for r in rop: |
| for c in countp: |
| for o in order: |
| for s in size: |
| for e in endian: |
| for n in nails: |
| for op in ops: |
| args.append((r, c, o, s, e, n, op)) |
| return args |
| |
| |
| def mpz_sizeinbase_data(api): |
| bases = list(map(str, range(2, 37))) |
| ops = gen_mpz_args(1000) + gen_mpzs( |
| count=1000, mindigits=100, maxdigits=2000) |
| return [(op, b) for op in ops for b in bases] |
| |
| |
| def get_str_data(ty): |
| bases = list(range(2, 37)) + list(range(-2, -37, -1)) |
| bases = list(map(str, bases)) |
| if ty == gmpapi.mpz_t: |
| ops = gen_mpz_args(1000) |
| elif ty == gmpapi.mpq_t: |
| ops = gen_mpq_args(20) |
| else: |
| raise RuntimeError("Unsupported get_str type: " + str(ty)) |
| return [("NULL", b, op) for b in bases for op in ops] |
| |
| |
| def mpz_get_str_data(api): |
| return get_str_data(gmpapi.mpz_t) |
| |
| |
| def mpq_get_str_data(api): |
| return get_str_data(gmpapi.mpq_t) |
| |
| |
| def mpq_set_str_data(api): |
| args = gen_mpq_args(20) + gen_mpz_args() |
| # zero does not match results exactly because the |
| # results are not canonicalized first. We choose to |
| # exclude zero from test results. The other option is |
| # to canonicalize the results after parsing the strings. |
| # Instead we exclude zero so that we can independently |
| # test correctness of set_str and canonicalization |
| nonzero = [] |
| for arg in args: |
| if "/" in arg: |
| pos = arg.find("/") |
| if int(arg[:pos]) != 0: |
| nonzero.append(arg) |
| elif int(arg) != 0: |
| nonzero.append(arg) |
| |
| return [("0", q, "10") for q in nonzero] |
| |
| |
| def get_div_data(n, d, rate=0.2): |
| """Generate some inputs that are perfectly divisible""" |
| if random.random() < rate: |
| n = mul_mpzs(n, d) |
| return (n, d) |
| |
| |
| def allow(name, args): |
| if name not in blacklists: |
| return True |
| filters = blacklists[name] |
| for (pos, disallow) in filters: |
| if args[pos] in disallow: |
| return False |
| return True |
| |
| |
| def fixup_args(name, args): |
| if name not in fixups: |
| return [args] |
| return fixups[name](args) |
| |
| |
| # list of values to be excluded for various api calls |
| # list format is (pos, [list of values to exclude]) |
| blacklists = { |
| "mpz_cdiv_q": [(2, ["0", "-0"])], |
| "mpz_fdiv_q": [(2, ["0", "-0"])], |
| "mpz_fdiv_r": [(2, ["0", "-0"])], |
| "mpz_tdiv_q": [(2, ["0", "-0"])], |
| "mpz_fdiv_q_ui": [(2, ["0", "-0"])], |
| "mpz_divexact": [(2, ["0", "-0"])], |
| "mpz_divisible_p": [(1, ["0", "-0"])], |
| "mpz_divexact_ui": [(2, ["0", "-0"])], |
| "mpq_set_ui": [(2, ["0", "-0"])], |
| } |
| |
| fixups = { |
| "mpz_divexact": mpz_divexact_data, |
| "mpz_divisible_p": mpz_divisible_p_data, |
| "mpz_cdiv_q": mpz_div3_data, |
| "mpz_fdiv_q": mpz_div3_data, |
| "mpz_fdiv_r": mpz_div3_data, |
| "mpz_tdiv_q": mpz_div3_data, |
| "mpz_fdiv_q_ui": mpz_div3_data, |
| "mpz_divexact_ui": mpz_divexact_data, |
| "mpz_pow_ui": mpz_pow_data, |
| "mpz_gcd": mpz_gcd_data, |
| "mpz_lcm": mpz_gcd_data, |
| "mpz_mul_2exp": mpz_mul_2exp_data, |
| } |
| |
| custom = { |
| "mpz_export": mpz_export_data, |
| "mpz_import": mpz_export_data, |
| "mpz_sizeinbase": mpz_sizeinbase_data, |
| "mpz_get_str": mpz_get_str_data, |
| "mpq_set_str": mpq_set_str_data, |
| "mpq_get_str": mpq_get_str_data, |
| } |
| |
| if __name__ == "__main__": |
| #apis = [gmpapi.get_api("mpq_set_str"),] |
| apis = gmpapi.apis |
| for api in apis: |
| tests = gen_args(api) |
| for args in tests: |
| expanded_args = fixup_args(api.name, args) |
| for args in expanded_args: |
| if allow(api.name, args): |
| print("{}|{}".format(api.name, ",".join(args))) |