Commit 87784c502d7bfa4d1f98f53b39fb4ea0bbee265d
1 parent
c0ca6bc6
Track results of Python unit tests (#1119)
The results of the Python unit test were not correctly tracked due to some subtle problems related to the way how C++ code is called through the Python interface. A kluge has been found and added to GTestSuite.i to retrieve the Python test results and to propagate them to the C++ test suite, so now Python test results are also written into the XML file, and the Python tests signal failure in case that something goes wrong.
Showing
4 changed files
with
62 additions
and
15 deletions
ChangeLog
| 1 | -2014-01-25 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> | 1 | +2014-01-29 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> |
| 2 | 2 | ||
| 3 | * Bug fix Version 0.8.1 released | 3 | * Bug fix Version 0.8.1 released |
| 4 | ================================ | 4 | ================================ |
| 5 | 5 | ||
| 6 | Added missing hyphens in pfiles synchronisation section (#1091) | 6 | Added missing hyphens in pfiles synchronisation section (#1091) |
| 7 | Add configuration test script (#1091) | 7 | Add configuration test script (#1091) |
| 8 | - GModelSky, GCTAModelBackground and GCTAModelRadialAcceptance write | ||
| 9 | - id attribute into XML file (#1092) | 8 | + GModelSky, GCTAModelBackground and GCTAModelRadialAcceptance write id attribute into XML file (#1092) |
| 10 | Add GChatter typedef to Python interface | 9 | Add GChatter typedef to Python interface |
| 11 | - GAMMALIB_CALDB takes precedence over CALDB environment var (#1094) | 10 | + GAMMALIB_CALDB takes precedence over CALDB environment variable (#1094) |
| 12 | Added vo module and GVOClient class to Python interface | 11 | Added vo module and GVOClient class to Python interface |
| 12 | + Track results of Python unit tests (#1119) | ||
| 13 | + | ||
| 13 | 14 | ||
| 14 | 2014-01-18 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> | 15 | 2014-01-18 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> |
| 15 | 16 |
NEWS
| @@ -2,7 +2,7 @@ New Features and Important Changes in GammaLib 00-08-01 | @@ -2,7 +2,7 @@ New Features and Important Changes in GammaLib 00-08-01 | ||
| 2 | 2 | ||
| 3 | Author(s) : Juergen Knoedlseder | 3 | Author(s) : Juergen Knoedlseder |
| 4 | 4 | ||
| 5 | -25 January 2014 | 5 | +29 January 2014 |
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | 1. Introduction | 8 | 1. Introduction |
| @@ -100,7 +100,12 @@ None | @@ -100,7 +100,12 @@ None | ||
| 100 | 100 | ||
| 101 | 17. Test module | 101 | 17. Test module |
| 102 | --------------- | 102 | --------------- |
| 103 | -None | 103 | +The results of the Python unit test were not correctly tracked due to |
| 104 | +some subtle problems related to the way how C++ code is called through the | ||
| 105 | +Python interface. A kluge has been found and added to GTestSuite.i to | ||
| 106 | +retrieve the Python test results and to propagate them to the C++ test | ||
| 107 | +suite, so now Python test results are also written into the XML file, and | ||
| 108 | +the Python tests signal failure in case that something goes wrong. | ||
| 104 | 109 | ||
| 105 | 110 | ||
| 106 | 18. Multi-wavelength interface | 111 | 18. Multi-wavelength interface |
pyext/GTestSuite.i
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * GTestSuite.i - Abstract test suite base class * | 2 | * GTestSuite.i - Abstract test suite base class * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2012-2013 Jean-Baptiste Cayrou * | 4 | + * copyright (C) 2012-2014 Jean-Baptiste Cayrou * |
| 5 | * ----------------------------------------------------------------------- * | 5 | * ----------------------------------------------------------------------- * |
| 6 | * * | 6 | * * |
| 7 | * This program is free software: you can redistribute it and/or modify * | 7 | * This program is free software: you can redistribute it and/or modify * |
| @@ -94,6 +94,8 @@ public: | @@ -94,6 +94,8 @@ public: | ||
| 94 | // Constructor | 94 | // Constructor |
| 95 | GPythonTestSuite(void) { | 95 | GPythonTestSuite(void) { |
| 96 | m_py_objects.clear(); | 96 | m_py_objects.clear(); |
| 97 | + m_py_names.clear(); | ||
| 98 | + m_py_suites.clear(); | ||
| 97 | } | 99 | } |
| 98 | 100 | ||
| 99 | // Destructor | 101 | // Destructor |
| @@ -107,34 +109,78 @@ public: | @@ -107,34 +109,78 @@ public: | ||
| 107 | void set(void) { | 109 | void set(void) { |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | - // Clone method | 112 | + // Clone method (implementation makes this class non-abstract) |
| 111 | GPythonTestSuite* clone(void) const { | 113 | GPythonTestSuite* clone(void) const { |
| 112 | return new GPythonTestSuite(*this); | 114 | return new GPythonTestSuite(*this); |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 115 | // Generic test function for Python callback | 117 | // Generic test function for Python callback |
| 116 | void test(void) { | 118 | void test(void) { |
| 119 | + | ||
| 120 | + // Initialise failures, errors and test cases before testing | ||
| 121 | + int failures = m_py_suites[m_index]->failures(); | ||
| 122 | + int errors = m_py_suites[m_index]->errors(); | ||
| 123 | + int cases = m_py_suites[m_index]->size(); | ||
| 124 | + | ||
| 125 | + // Execute unit test suite | ||
| 117 | PyObject* args = Py_BuildValue("()"); | 126 | PyObject* args = Py_BuildValue("()"); |
| 118 | PyObject* func = static_cast<PyObject*>(m_py_objects[m_index]); | 127 | PyObject* func = static_cast<PyObject*>(m_py_objects[m_index]); |
| 119 | PyObject* res = PyEval_CallObject(func, args); | 128 | PyObject* res = PyEval_CallObject(func, args); |
| 120 | Py_DECREF(args); | 129 | Py_DECREF(args); |
| 130 | + | ||
| 131 | + // Handle any error that occured during the test | ||
| 121 | if (res == NULL) { | 132 | if (res == NULL) { |
| 122 | throw GPythonException::test_error("GPythonTestSuite::test"); | 133 | throw GPythonException::test_error("GPythonTestSuite::test"); |
| 123 | } | 134 | } |
| 124 | else { | 135 | else { |
| 125 | Py_DECREF(res); | 136 | Py_DECREF(res); |
| 126 | } | 137 | } |
| 138 | + | ||
| 139 | + // Determine failures and errors after testing | ||
| 140 | + m_failures += (m_py_suites[m_index]->failures() - failures); | ||
| 141 | + m_errors += (m_py_suites[m_index]->errors() - errors); | ||
| 142 | + | ||
| 143 | + // Recover test cases | ||
| 144 | + for (int i = cases; i < m_py_suites[m_index]->size(); ++i) { | ||
| 145 | + | ||
| 146 | + // Get actual test case | ||
| 147 | + GTestCase& test = (*m_py_suites[m_index])[i]; | ||
| 148 | + | ||
| 149 | + // Kluge to set the test name correctly. For some reason, the | ||
| 150 | + // m_index points to the first test case when the Python | ||
| 151 | + // function is called, hence the name of the first test case | ||
| 152 | + // gets prepended. The name is thus replaced by the correct | ||
| 153 | + // name for all test cases following the first test case. | ||
| 154 | + if (m_index > 0) { | ||
| 155 | + std::string name = test.name(); | ||
| 156 | + name.erase(0, m_names[0].length()); | ||
| 157 | + name = m_names[m_index] + name; | ||
| 158 | + test.name(name); | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + // Clone the test case and push it on stack | ||
| 162 | + m_tests.push_back(new GTestCase(test)); | ||
| 163 | + | ||
| 164 | + } // endfor: looped over all test cases | ||
| 165 | + | ||
| 166 | + // Return | ||
| 127 | return; | 167 | return; |
| 128 | } | 168 | } |
| 129 | 169 | ||
| 130 | // Append Python callback to function lists | 170 | // Append Python callback to function lists |
| 131 | void append(PyObject* function, const std::string& name) { | 171 | void append(PyObject* function, const std::string& name) { |
| 132 | m_py_objects.push_back(function); | 172 | m_py_objects.push_back(function); |
| 173 | + m_py_names.push_back(name); | ||
| 174 | + m_py_suites.push_back(this); | ||
| 133 | Py_INCREF(function); | 175 | Py_INCREF(function); |
| 134 | this->GTestSuite::append(static_cast<pfunction>(&GPythonTestSuite::test), | 176 | this->GTestSuite::append(static_cast<pfunction>(&GPythonTestSuite::test), |
| 135 | name); | 177 | name); |
| 136 | } | 178 | } |
| 137 | - std::vector<PyObject*> m_py_objects; //!< Python callback function list | 179 | + |
| 180 | + // Callback information | ||
| 181 | + std::vector<PyObject*> m_py_objects; //!< Python callback function list | ||
| 182 | + std::vector<std::string> m_py_names; //!< Python callback function names | ||
| 183 | + std::vector<GTestSuite*> m_py_suites; //!< Python callback function pointers | ||
| 138 | }; | 184 | }; |
| 139 | %} | 185 | %} |
| 140 | 186 | ||
| @@ -194,11 +240,6 @@ public: | @@ -194,11 +240,6 @@ public: | ||
| 194 | * @brief GTestSuite class extension | 240 | * @brief GTestSuite class extension |
| 195 | ***************************************************************************/ | 241 | ***************************************************************************/ |
| 196 | %extend GTestSuite { | 242 | %extend GTestSuite { |
| 197 | - /* | ||
| 198 | - char *__str__() { | ||
| 199 | - return gammalib::tochar(self->print()); | ||
| 200 | - } | ||
| 201 | - */ | ||
| 202 | GTestCase& __getitem__(const int& index) { | 243 | GTestCase& __getitem__(const int& index) { |
| 203 | if (index >= 0 && index < self->size()) { | 244 | if (index >= 0 && index < self->size()) { |
| 204 | return (*self)[index]; | 245 | return (*self)[index]; |
src/test/GTestSuite.cpp
| @@ -389,9 +389,9 @@ void GTestSuite::test_assert(const bool& assert, | @@ -389,9 +389,9 @@ void GTestSuite::test_assert(const bool& assert, | ||
| 389 | 389 | ||
| 390 | // Return | 390 | // Return |
| 391 | return; | 391 | return; |
| 392 | - | ||
| 393 | } | 392 | } |
| 394 | 393 | ||
| 394 | + | ||
| 395 | /***********************************************************************//** | 395 | /***********************************************************************//** |
| 396 | * @brief Test a value | 396 | * @brief Test a value |
| 397 | * | 397 | * |