17db96d56Sopenharmony_ci/* Poor-man's template.  Macros used:
27db96d56Sopenharmony_ci   TESTNAME     name of the test (like test_long_api_inner)
37db96d56Sopenharmony_ci   TYPENAME     the signed type (like long)
47db96d56Sopenharmony_ci   F_S_TO_PY    convert signed to pylong; TYPENAME -> PyObject*
57db96d56Sopenharmony_ci   F_PY_TO_S    convert pylong to signed; PyObject* -> TYPENAME
67db96d56Sopenharmony_ci   F_U_TO_PY    convert unsigned to pylong; unsigned TYPENAME -> PyObject*
77db96d56Sopenharmony_ci   F_PY_TO_U    convert pylong to unsigned; PyObject* -> unsigned TYPENAME
87db96d56Sopenharmony_ci*/
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_cistatic PyObject *
117db96d56Sopenharmony_ciTESTNAME(PyObject *error(const char*))
127db96d56Sopenharmony_ci{
137db96d56Sopenharmony_ci    const int NBITS = sizeof(TYPENAME) * 8;
147db96d56Sopenharmony_ci    unsigned TYPENAME base;
157db96d56Sopenharmony_ci    PyObject *pyresult;
167db96d56Sopenharmony_ci    int i;
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_ci    /* Note:  This test lets PyObjects leak if an error is raised.  Since
197db96d56Sopenharmony_ci       an error should never be raised, leaks are impossible <wink>. */
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci    /* Test native -> PyLong -> native roundtrip identity.
227db96d56Sopenharmony_ci     * Generate all powers of 2, and test them and their negations,
237db96d56Sopenharmony_ci     * plus the numbers +-1 off from them.
247db96d56Sopenharmony_ci     */
257db96d56Sopenharmony_ci    base = 1;
267db96d56Sopenharmony_ci    for (i = 0;
277db96d56Sopenharmony_ci         i < NBITS + 1;  /* on last, base overflows to 0 */
287db96d56Sopenharmony_ci         ++i, base <<= 1)
297db96d56Sopenharmony_ci    {
307db96d56Sopenharmony_ci        int j;
317db96d56Sopenharmony_ci        for (j = 0; j < 6; ++j) {
327db96d56Sopenharmony_ci            TYPENAME in, out;
337db96d56Sopenharmony_ci            unsigned TYPENAME uin, uout;
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci            /* For 0, 1, 2 use base; for 3, 4, 5 use -base */
367db96d56Sopenharmony_ci            uin = j < 3 ? base : 0U - base;
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci            /* For 0 & 3, subtract 1.
397db96d56Sopenharmony_ci             * For 1 & 4, leave alone.
407db96d56Sopenharmony_ci             * For 2 & 5, add 1.
417db96d56Sopenharmony_ci             */
427db96d56Sopenharmony_ci            uin += (unsigned TYPENAME)(TYPENAME)(j % 3 - 1);
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci            pyresult = F_U_TO_PY(uin);
457db96d56Sopenharmony_ci            if (pyresult == NULL)
467db96d56Sopenharmony_ci                return error(
477db96d56Sopenharmony_ci                 "unsigned unexpected null result");
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci            uout = F_PY_TO_U(pyresult);
507db96d56Sopenharmony_ci            if (uout == (unsigned TYPENAME)-1 && PyErr_Occurred())
517db96d56Sopenharmony_ci                return error(
527db96d56Sopenharmony_ci                    "unsigned unexpected -1 result");
537db96d56Sopenharmony_ci            if (uout != uin)
547db96d56Sopenharmony_ci                return error(
557db96d56Sopenharmony_ci                    "unsigned output != input");
567db96d56Sopenharmony_ci            UNBIND(pyresult);
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci            in = (TYPENAME)uin;
597db96d56Sopenharmony_ci            pyresult = F_S_TO_PY(in);
607db96d56Sopenharmony_ci            if (pyresult == NULL)
617db96d56Sopenharmony_ci                return error(
627db96d56Sopenharmony_ci                    "signed unexpected null result");
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci            out = F_PY_TO_S(pyresult);
657db96d56Sopenharmony_ci            if (out == (TYPENAME)-1 && PyErr_Occurred())
667db96d56Sopenharmony_ci                return error(
677db96d56Sopenharmony_ci                    "signed unexpected -1 result");
687db96d56Sopenharmony_ci            if (out != in)
697db96d56Sopenharmony_ci                return error(
707db96d56Sopenharmony_ci                    "signed output != input");
717db96d56Sopenharmony_ci            UNBIND(pyresult);
727db96d56Sopenharmony_ci        }
737db96d56Sopenharmony_ci    }
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci    /* Overflow tests.  The loop above ensured that all limit cases that
767db96d56Sopenharmony_ci     * should not overflow don't overflow, so all we need to do here is
777db96d56Sopenharmony_ci     * provoke one-over-the-limit cases (not exhaustive, but sharp).
787db96d56Sopenharmony_ci     */
797db96d56Sopenharmony_ci    {
807db96d56Sopenharmony_ci        PyObject *one, *x, *y;
817db96d56Sopenharmony_ci        TYPENAME out;
827db96d56Sopenharmony_ci        unsigned TYPENAME uout;
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci        one = PyLong_FromLong(1);
857db96d56Sopenharmony_ci        if (one == NULL)
867db96d56Sopenharmony_ci            return error(
877db96d56Sopenharmony_ci                "unexpected NULL from PyLong_FromLong");
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ci        /* Unsigned complains about -1? */
907db96d56Sopenharmony_ci        x = PyNumber_Negative(one);
917db96d56Sopenharmony_ci        if (x == NULL)
927db96d56Sopenharmony_ci            return error(
937db96d56Sopenharmony_ci                "unexpected NULL from PyNumber_Negative");
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci        uout = F_PY_TO_U(x);
967db96d56Sopenharmony_ci        if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
977db96d56Sopenharmony_ci            return error(
987db96d56Sopenharmony_ci                "PyLong_AsUnsignedXXX(-1) didn't complain");
997db96d56Sopenharmony_ci        if (!PyErr_ExceptionMatches(PyExc_OverflowError))
1007db96d56Sopenharmony_ci            return error(
1017db96d56Sopenharmony_ci                "PyLong_AsUnsignedXXX(-1) raised "
1027db96d56Sopenharmony_ci                "something other than OverflowError");
1037db96d56Sopenharmony_ci        PyErr_Clear();
1047db96d56Sopenharmony_ci        UNBIND(x);
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci        /* Unsigned complains about 2**NBITS? */
1077db96d56Sopenharmony_ci        y = PyLong_FromLong((long)NBITS);
1087db96d56Sopenharmony_ci        if (y == NULL)
1097db96d56Sopenharmony_ci            return error(
1107db96d56Sopenharmony_ci                "unexpected NULL from PyLong_FromLong");
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci        x = PyNumber_Lshift(one, y); /* 1L << NBITS, == 2**NBITS */
1137db96d56Sopenharmony_ci        UNBIND(y);
1147db96d56Sopenharmony_ci        if (x == NULL)
1157db96d56Sopenharmony_ci            return error(
1167db96d56Sopenharmony_ci                "unexpected NULL from PyNumber_Lshift");
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci        uout = F_PY_TO_U(x);
1197db96d56Sopenharmony_ci        if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
1207db96d56Sopenharmony_ci            return error(
1217db96d56Sopenharmony_ci                "PyLong_AsUnsignedXXX(2**NBITS) didn't "
1227db96d56Sopenharmony_ci                "complain");
1237db96d56Sopenharmony_ci        if (!PyErr_ExceptionMatches(PyExc_OverflowError))
1247db96d56Sopenharmony_ci            return error(
1257db96d56Sopenharmony_ci                "PyLong_AsUnsignedXXX(2**NBITS) raised "
1267db96d56Sopenharmony_ci                "something other than OverflowError");
1277db96d56Sopenharmony_ci        PyErr_Clear();
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ci        /* Signed complains about 2**(NBITS-1)?
1307db96d56Sopenharmony_ci           x still has 2**NBITS. */
1317db96d56Sopenharmony_ci        y = PyNumber_Rshift(x, one); /* 2**(NBITS-1) */
1327db96d56Sopenharmony_ci        UNBIND(x);
1337db96d56Sopenharmony_ci        if (y == NULL)
1347db96d56Sopenharmony_ci            return error(
1357db96d56Sopenharmony_ci                "unexpected NULL from PyNumber_Rshift");
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci        out = F_PY_TO_S(y);
1387db96d56Sopenharmony_ci        if (out != (TYPENAME)-1 || !PyErr_Occurred())
1397db96d56Sopenharmony_ci            return error(
1407db96d56Sopenharmony_ci                "PyLong_AsXXX(2**(NBITS-1)) didn't "
1417db96d56Sopenharmony_ci                "complain");
1427db96d56Sopenharmony_ci        if (!PyErr_ExceptionMatches(PyExc_OverflowError))
1437db96d56Sopenharmony_ci            return error(
1447db96d56Sopenharmony_ci                "PyLong_AsXXX(2**(NBITS-1)) raised "
1457db96d56Sopenharmony_ci                "something other than OverflowError");
1467db96d56Sopenharmony_ci        PyErr_Clear();
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ci        /* Signed complains about -2**(NBITS-1)-1?;
1497db96d56Sopenharmony_ci           y still has 2**(NBITS-1). */
1507db96d56Sopenharmony_ci        x = PyNumber_Negative(y);  /* -(2**(NBITS-1)) */
1517db96d56Sopenharmony_ci        UNBIND(y);
1527db96d56Sopenharmony_ci        if (x == NULL)
1537db96d56Sopenharmony_ci            return error(
1547db96d56Sopenharmony_ci                "unexpected NULL from PyNumber_Negative");
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci        y = PyNumber_Subtract(x, one); /* -(2**(NBITS-1))-1 */
1577db96d56Sopenharmony_ci        UNBIND(x);
1587db96d56Sopenharmony_ci        if (y == NULL)
1597db96d56Sopenharmony_ci            return error(
1607db96d56Sopenharmony_ci                "unexpected NULL from PyNumber_Subtract");
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_ci        out = F_PY_TO_S(y);
1637db96d56Sopenharmony_ci        if (out != (TYPENAME)-1 || !PyErr_Occurred())
1647db96d56Sopenharmony_ci            return error(
1657db96d56Sopenharmony_ci                "PyLong_AsXXX(-2**(NBITS-1)-1) didn't "
1667db96d56Sopenharmony_ci                "complain");
1677db96d56Sopenharmony_ci        if (!PyErr_ExceptionMatches(PyExc_OverflowError))
1687db96d56Sopenharmony_ci            return error(
1697db96d56Sopenharmony_ci                "PyLong_AsXXX(-2**(NBITS-1)-1) raised "
1707db96d56Sopenharmony_ci                "something other than OverflowError");
1717db96d56Sopenharmony_ci        PyErr_Clear();
1727db96d56Sopenharmony_ci        UNBIND(y);
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci        Py_XDECREF(x);
1757db96d56Sopenharmony_ci        Py_XDECREF(y);
1767db96d56Sopenharmony_ci        Py_DECREF(one);
1777db96d56Sopenharmony_ci    }
1787db96d56Sopenharmony_ci
1797db96d56Sopenharmony_ci    /* Test F_PY_TO_{S,U} on non-pylong input. This should raise a TypeError. */
1807db96d56Sopenharmony_ci    {
1817db96d56Sopenharmony_ci        TYPENAME out;
1827db96d56Sopenharmony_ci        unsigned TYPENAME uout;
1837db96d56Sopenharmony_ci
1847db96d56Sopenharmony_ci        Py_INCREF(Py_None);
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci        out = F_PY_TO_S(Py_None);
1877db96d56Sopenharmony_ci        if (out != (TYPENAME)-1 || !PyErr_Occurred())
1887db96d56Sopenharmony_ci            return error("PyLong_AsXXX(None) didn't complain");
1897db96d56Sopenharmony_ci        if (!PyErr_ExceptionMatches(PyExc_TypeError))
1907db96d56Sopenharmony_ci            return error("PyLong_AsXXX(None) raised "
1917db96d56Sopenharmony_ci                         "something other than TypeError");
1927db96d56Sopenharmony_ci        PyErr_Clear();
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci        uout = F_PY_TO_U(Py_None);
1957db96d56Sopenharmony_ci        if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
1967db96d56Sopenharmony_ci            return error("PyLong_AsXXX(None) didn't complain");
1977db96d56Sopenharmony_ci        if (!PyErr_ExceptionMatches(PyExc_TypeError))
1987db96d56Sopenharmony_ci            return error("PyLong_AsXXX(None) raised "
1997db96d56Sopenharmony_ci                         "something other than TypeError");
2007db96d56Sopenharmony_ci        PyErr_Clear();
2017db96d56Sopenharmony_ci
2027db96d56Sopenharmony_ci        Py_DECREF(Py_None);
2037db96d56Sopenharmony_ci    }
2047db96d56Sopenharmony_ci
2057db96d56Sopenharmony_ci    Py_INCREF(Py_None);
2067db96d56Sopenharmony_ci    return Py_None;
2077db96d56Sopenharmony_ci}
208