diff -r ce39a4ec2906 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Thu May 10 05:16:41 2012 +0200 +++ b/Modules/_testcapimodule.c Thu May 10 01:34:20 2012 -0700 @@ -1194,49 +1194,121 @@ Py_RETURN_NONE; } +static int got_impossible_format_unit(int format_unit, int parse_result) { + int result = 0; + PyObject *type; + PyObject *value; + PyObject *traceback; + + /* if parsing succeeded, this cannot be an impossible format unit */ + if (parse_result) + return 0; + + PyErr_Fetch(&type, &value, &traceback); + + if (type && value) { + if (type == PyExc_TypeError) { + PyObject *s = PyUnicode_FromString("argument 1 must be impossible, not int"); + result = !PyUnicode_Compare(value, s); + Py_DECREF(s); + } + else if (type == PyExc_RuntimeError) { + PyObject *s = PyUnicode_FromFormat("impossible: '%ci'", format_unit); + result = !PyUnicode_Compare(value, s); + Py_DECREF(s); + } + } + + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + return result; +} + static PyObject * -test_bug_7414(PyObject *self) +test_skipitem_parity(PyObject *self) { - /* Issue #7414: for PyArg_ParseTupleAndKeywords, 'C' code wasn't being - skipped properly in skipitem() */ - int a = 0, b = 0, result; - char *kwlist[] = {"a", "b", NULL}; - PyObject *tuple = NULL, *dict = NULL, *b_str; + /* + * If this test failed, you probably added a new "format unit" + * in Python/getargs.c, but neglected to update our poor friend + * skipitem() in the same file. (If so, shame on you!) + * + * This function brute-force tests all** ASCII characters (1 to 127 + * inclusive) as format units, checking to see that + * PyArg_ParseTupleAndKeywords() return consistent errors both when + * the unit is attempted to be used and when it is skipped. If the + * format unit doesn't exist, we'll get one of two specific error + * messages (one for used, one for skipped); if it does exist we + * *won't* get that error--we'll get either no error or some other + * error. If we get the "does not exist" error for one test and + * not for the other, there's a mismatch, and the test fails. + * + * ** Okay, it actually skips some ASCII characters. Some characters + * have special funny semantics, and it would be difficult to + * accomodate them here. + */ + int i; + int result; + char format[8]; + char output_a[64]; + char output_b[64]; + char when_not_skipped; + char when_skipped; + PyObject *empty_tuple; + PyObject *tuple_1; + PyObject *dict_b; + static char *keywords[] = {"a", "b", NULL}; - tuple = PyTuple_New(0); - if (tuple == NULL) - goto failure; - dict = PyDict_New(); - if (dict == NULL) - goto failure; - b_str = PyUnicode_FromString("b"); - if (b_str == NULL) - goto failure; - result = PyDict_SetItemString(dict, "b", b_str); - Py_DECREF(b_str); - if (result < 0) - goto failure; + /* + * Python C source files must be ASCII, + * therefore we will never have a format unit > 127 + */ + for (i = 1; i < 128; i++) { + switch (i) { + /* skip parentheses, the error reporting is inconsistent about them */ + case '(': + case ')': + /* skip 'e', it is always a two-character code */ + case 'e': + /* skip '|' and '$', they don't represent arguments anyway */ + case '|': + case '$': + continue; - result = PyArg_ParseTupleAndKeywords(tuple, dict, "|CC", - kwlist, &a, &b); - if (!result) - goto failure; + default: + break; + } - if (a != 0) - return raiseTestError("test_bug_7414", - "C format code not skipped properly"); - if (b != 'b') - return raiseTestError("test_bug_7414", - "C format code returned wrong value"); + empty_tuple = PyTuple_New(0); + tuple_1 = PyTuple_New(1); + PyTuple_SetItem(tuple_1, 0, PyLong_FromLong(1)); + dict_b = PyDict_New(); + PyDict_SetItemString(dict_b, "b", PyLong_FromLong(1)); - Py_DECREF(dict); - Py_DECREF(tuple); + /* test the format unit when not skipped */ + sprintf(format, "%ci", i); + result = PyArg_ParseTupleAndKeywords(tuple_1, dict_b, + format, keywords, &(output_a[0]), &(output_b[0])); + when_not_skipped = got_impossible_format_unit(i, result); + + /* test the format unit when skipped */ + sprintf(format, "|%ci", i); + result = PyArg_ParseTupleAndKeywords(empty_tuple, dict_b, + format, keywords, &(output_a[0]), &(output_b[0])); + when_skipped = got_impossible_format_unit(i, result); + + Py_DECREF(empty_tuple); + Py_DECREF(tuple_1); + Py_DECREF(dict_b); + + if (when_not_skipped != when_skipped) { + return PyErr_Format(PyExc_RuntimeError, "test_skipitem_parity: " + "detected mismatch between convertsimple and skipitem " + "for '%c' (%d)", i, i); + } + } + Py_RETURN_NONE; - - failure: - Py_XDECREF(dict); - Py_XDECREF(tuple); - return NULL; } @@ -2426,7 +2498,7 @@ {"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS}, {"test_k_code", (PyCFunction)test_k_code, METH_NOARGS}, {"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS}, - {"test_bug_7414", (PyCFunction)test_bug_7414, METH_NOARGS}, + {"test_skipitem_parity", (PyCFunction)test_skipitem_parity, METH_NOARGS}, {"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS}, {"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS}, {"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS,