You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
12 KiB

  1. # Testing KiCad #
  2. [TOC]
  3. # Unit tests {#unit-tests}
  4. KiCad has a limited number of unit tests, which can be used to
  5. check that certain functionality works.
  6. Tests are registered using [CTest][], part of CMake. CTest gathers all the
  7. disparate test programs and runs them. Most C++ unit
  8. tests are written using the [Boost Unit Test framework][], but this is not
  9. required to add a test to the testing suite.
  10. The test CMake targets generally start with `qa_`, the names of the tests
  11. within CTest are the same but without the `qa_` prefix.
  12. ## Running tests {#running-tests}
  13. You can run all tests after building with `make test` or `ctest`. The latter
  14. option allows many CTest options which can be useful, especially in automated
  15. or CI environments.
  16. ### Running specific tests {#running-specific-tests}
  17. To run a specific test executable, you can just run with `ctest` or run
  18. the executable directly. Running directly is often the simplest way when
  19. working on a specific test and you want access to the test executable's
  20. arguments. For example:
  21. # run the libcommon tests
  22. cd /path/to/kicad/build
  23. qa/common/qa_common [parameters]
  24. For Boost unit tests, you can see the options for the test with `<test> --help`.
  25. Common useful patterns:
  26. * `<test> -t "Utf8/*"` runs all tests in the `Utf8` test suite.
  27. * `<test> -t "Utf8/UniIterNull"` runs only a single test in a specific suite.
  28. * `<test> -l all` adds more verbose debugging to the output.
  29. * `<test> --list_content` lists the test suites and test cases within the
  30. test program. You can use these for arguments to `-t`.
  31. You can rebuild just a specific test with CMake to avoid rebuilding
  32. everything when working on a small area, e.g. `make qa_common`.
  33. ### Automated testing {#automated-testing}
  34. The unit tests can be run on automated Continuous Integration (CI) systems.
  35. By default, tests output human-readable results, which is useful when
  36. developing or debugging, but not so useful for automated test reporting.
  37. Systems that can parse XML test results can enable these by setting the
  38. `KICAD_TEST_XML_OUTPUT` option to `ON`. The test results are then output
  39. as files ending in `.xml` in the `qa` subdirectory.
  40. Test results are written to the build directory as follows:
  41. * Boost units tests: one XML file per test with the extension `.boost-results.xml`
  42. * Python unit tests: one directory per test with the extension `.xunit-results.xml`.
  43. These directories contain one `.xml` file per Python test case file.
  44. ## Writing Boost tests {#writing-boost-tests}
  45. Boost unit tests are straightforward to write. Individual test cases can be
  46. registered with:
  47. BOOST_AUTO_TEST_CASE( SomeTest )
  48. {
  49. BOOST_CHECK_EQUAL( 1, 1 );
  50. }
  51. There is a range of functions like `BOOST_CHECK`, which are documented
  52. [here][boost-test-functions]. Using the most specific function is preferred, as that
  53. allows Boost to provide more detailed failures: `BOOST_CHECK( foo == bar )` only
  54. reports a mismatch, `BOOST_CHECK_EQUAL( foo, bar )` will show the values of
  55. each.
  56. To output debug messages, you can use `BOOST_TEST_MESSAGE` in the unit tests,
  57. which will be visible only if you set the `-l` parameter to `message` or higher.
  58. This colours the text differently to make it stand out from other testing
  59. messages and standard output.
  60. You can also use `std::cout`, `printf`, `wxLogDebug` and so on for debug
  61. messages inside tested functions (i.e. where you don't have access to the Boost
  62. unit test headers). These will always be printed, so take care
  63. to remove them before committing, or they'll show up when KiCad runs normally!
  64. ### Expected failures {#expected-failures}
  65. Sometimes, it is helpful to check in tests that do not pass. However, it is bad
  66. practise to intentionally check in commits that break builds (which is what
  67. happens if you cause `make test` to fail).
  68. Boost provides a method of declaring that some specific tests are allowed to fail.
  69. This syntax is not consistently available in all supported Boost versions, so you
  70. should use the following construct:
  71. ```
  72. #include <unit_test_utils/unit_test_utils.h>
  73. // On platforms with older boosts, the test will be excluded entirely
  74. #ifdef HAVE_EXPECTED_FAILURES
  75. // Declare a test case with 1 "allowed" failure (out of 2, in this case)
  76. BOOST_AUTO_TEST_CASE( SomeTest, *boost::unit_test::expected_failures( 1 ) )
  77. {
  78. BOOST_CHECK_EQUAL( 1, 1 );
  79. // This check fails, but does not cause a test suite failure
  80. BOOST_CHECK_EQUAL( 1, 2 );
  81. // Further failures *would* be a test suit failure
  82. }
  83. #endif
  84. ```
  85. When run, this produces output somewhat like this:
  86. ```
  87. qa/common/test_mytest.cpp(123): error: in "MyTests/SomeTest": check 1 == 2 has failed [1 != 2
  88. *** No errors detected
  89. ```
  90. And the unit test executable returns `0` (success).
  91. Checking in a failing test is a strictly temporary situation, used to illustrate
  92. the triggering of a bug prior to fixing it. This is advantageous, not only from
  93. a "project history" perspective, but also to ensure that the test you write to
  94. catch the bug in question does, in fact, catch the bug in the first place.
  95. ### Assertions {#test-assertions}
  96. It is possible to check for assertions in unit tests. When running the unit
  97. tests, `wxASSERT` calls are caught and re-thrown as exceptions. You can then use
  98. the `CHECK_WX_ASSERT` macro to check this is called in Debug builds. In Release
  99. builds, the check is not run, as `wxASSERT` is disabled in these builds.
  100. You can use this to ensure that code rejects invalid input correctly.
  101. ## Python modules {#python-tests}
  102. The Pcbnew Python modules have some test programs in the `qa` directory.
  103. You must have the `KICAD_SCRIPTING_MODULES` option on in CMake to
  104. build the modules and enable this target.
  105. The main test script is `qa/test.py` and the test units are in
  106. `qa/testcases`. All the test units can by run using `ctest python`, which
  107. runs `test.py`.
  108. You can also run an individual case manually, by making sure the
  109. modules are built, adding them to `PYTHONPATH` and running the test
  110. from the source tree:
  111. make pcbnew_python_module
  112. export PYTHONPATH=/path/to/kicad/build/pcbnew
  113. cd /path/to/kicad/source/qa
  114. python2 testcase/test_001_pcb_load.py
  115. ### Diagnosing segfaults {#python-segfaults}
  116. Although the module is Python, it links against a C++ library
  117. (the same one used by KiCad Pcbnew), so it can segfault if the library
  118. has a defect.
  119. You can run the tests in GDB to trace this:
  120. $ gdb
  121. (gdb) file python2
  122. (gdb) run testcases/test_001_pcb_load.py
  123. If the test segfaults, you will get a familiar backtrace, just like
  124. if you were running pcbnew under GDB.
  125. # Utility programs {#utility-programs}
  126. KiCad includes some utility programs that can be used for debugging, profiling,
  127. analysing or developing certain parts of the code without having to invoke the full
  128. GUI program.
  129. Generally, they are part of the `qa_*_tools` QA executables, each one containing
  130. the relevant tools for that library. To list the tools in a given program, pass
  131. the `-l` parameter. Most tools provide help with the `-h` argument.
  132. To invoke a program:
  133. qa_<lib>_tools <tool name> [-h] [tool arguments]
  134. Below is a brief outline of some available tools. For full information and command-line
  135. parameters, refer to the tools' usage test (`-h`).
  136. * `common_tools` (the common library and core functions):
  137. * `coroutine`: A simple coroutine example
  138. * `io_benchmark`: Show relative speeds of reading files using various IO techniques.
  139. * `qa_pcbnew_tools` (pcbnew-related functions):
  140. * `drc`: Run and benchmark certain DRC functions on a user-provided `.kicad_pcb` files
  141. * `pcb_parser`: Parse user-provided `.kicad_pcb` files
  142. * `polygon_generator`: Dump polygons found on a PCB to the console
  143. * `polygon_triangulation`: Perform triangulation of zone polygons on PCBs
  144. # Fuzz testing {#fuzz-testing}
  145. It is possible to run fuzz testing on some parts of KiCad. To do this for a
  146. generic function, you need to be able to pass some kind of input from the fuzz
  147. testing tool to the function under test.
  148. For example, to use the [AFL fuzzing tool][], you will need:
  149. * A test executable that can:
  150. * Receive input from `stdin` to be run by `afl-fuzz`.
  151. * Optional: process input from a filename to allow `afl-tmin` to minimise the
  152. input files.
  153. * To compile this executable with an AFL compiler, to enable the instrumentation
  154. that allows the fuzzer to detect the fuzzing state.
  155. For example, the `qa_pcbnew_tools` executable (which contains `pcb_parser`,
  156. a fuzz testing tool for `.kicad_pcb` file parsing) can be compiled like this:
  157. mkdir build
  158. cd build
  159. cmake -DCMAKE_CXX_COMPILER=/usr/bin/afl-clang-fast++ -DCMAKE_C_COMPILER=/usr/bin/afl-clang-fast ../kicad_src
  160. make qa_pcbnew_tools
  161. You may need to disable core dumps and CPU frequency scaling on your system (AFL
  162. will warn you if you should do this). For example, as root:
  163. # echo core >/proc/sys/kernel/core_pattern
  164. # echo performance | tee cpu*/cpufreq/scaling_governor
  165. To fuzz, run the executable via `afl-fuzz`:
  166. afl-fuzz -i fuzzin -o fuzzout -m500 qa/pcbnew_tools/qa_pcbnew_tools pcb_parser
  167. where:
  168. * `-i` is a directory of files to use as fuzz input "seeds"
  169. * `-o` is a directory to write the results (including inputs that provoke crashes
  170. or hangs)
  171. * `-t` is the maximum time that a run is allowed to take before being declared a "hang"
  172. * `-m` is the memory allowed to use (this often needs to be bumped, as KiCad code
  173. tends to use a lot of memory to initialise)
  174. The AFL TUI will then display the fuzzing progress, and you can use the hang- or
  175. crash-provoking inputs to debug code as needed.
  176. # Run-time debugging {#run-time}
  177. KiCad can be debugged at run-time, either under a full debugger
  178. such as GDB, or using simple methods like logging debug to the
  179. console.
  180. ## Printing debug {#print-debug}
  181. If you are compiling KiCad yourself, you can simply add debugging statements to
  182. relevant places in the code, for example:
  183. wxLogDebug( "Value of variable: %d", my_int );
  184. This produces debug output that can only be seen when compiling
  185. in Debug mode.
  186. You can also use `std::cout` and `printf`.
  187. Ensure you do not leave this kind of debugging in place when
  188. submitting code.
  189. ## Printing trace {#trace-debug}
  190. Some parts of the code have "trace" that can be enabled selectively according to
  191. a "mask", for example:
  192. wxLogTrace( "TRACEMASK", "My trace, value: %d", my_int );
  193. This will not be printed by default. To show it, set the `WXTRACE` environment
  194. variable when you run KiCad to include the masks you wish to enable:
  195. $ WXTRACE="TRACEMASK,OTHERMASK" kicad
  196. When printed, the debug will be prefixed with a timestamp and the trace mask:
  197. 11:22:33: Trace: (TRACEMASK) My trace, value: 42
  198. If you add a trace mask, define and document the mask as a variable in
  199. `include/trace_helpers.h`. This will add it to the [trace mask documentation][].
  200. Some available masks:
  201. * Core KiCad functions:
  202. * `KICAD_KEY_EVENTS`
  203. * `KicadScrollSettings`
  204. * `KICAD_FIND_ITEM`
  205. * `KICAD_FIND_REPLACE`
  206. * `KICAD_NGSPICE`
  207. * `KICAD_PLUGINLOADER`
  208. * `GAL_PROFILE`
  209. * `GAL_CACHED_CONTAINER`
  210. * `PNS`
  211. * `CN`
  212. * `SCROLL_ZOOM` - for the scroll-wheel zooming logic in GAL
  213. * Plugin-specific (including "standard" KiCad formats):
  214. * `3D_CACHE`
  215. * `3D_SG`
  216. * `3D_RESOLVER`
  217. * `3D_PLUGIN_MANAGER`
  218. * `KI_TRACE_CCAMERA`
  219. * `PLUGIN_IDF`
  220. * `PLUGIN_VRML`
  221. * `KICAD_SCH_LEGACY_PLUGIN`
  222. * `KICAD_GEDA_PLUGIN`
  223. * `KICAD_PCB_PLUGIN`
  224. # Advanced configuration {#advanced-configuration}
  225. There are some advance configuration options, which are mostly used for
  226. development or testing purposes.
  227. To set these options, you can create the file `kicad_advanced` and set the keys
  228. as desired (the [advanced config documentation][] for a current list. You should
  229. never need to set these keys for normal usage - if you do, that's a bug.
  230. Any features enabled though the advanced configuration system are
  231. considered experimental and therefore unsuitable for production use. These
  232. features are explicitly not supported or considered fully tested.
  233. Issues are still welcome for defects discovered.
  234. [CTest]: https://cmake.org/cmake/help/latest/module/CTest.html
  235. [Boost Unit Test framework]: https://www.boost.org/doc/libs/1_68_0/libs/test/doc/html/index.html
  236. [boost-test-functions]: https://www.boost.org/doc/libs/1_68_0/libs/test/doc/html/boost_test/utf_reference/testing_tool_ref.html
  237. [AFL fuzzing tool]: http://lcamtuf.coredump.cx/afl/
  238. [trace mask documentation]: http://docs.kicad-pcb.org/doxygen/group__trace__env__vars.html
  239. [trace mask documentation]: http://docs.kicad-pcb.org/doxygen/group__trace__env__vars.html
  240. [advanced config documentation]: http://docs.kicad-pcb.org/doxygen/namespaceAC__KEYS.html