← Back to team overview

kicad-developers team mailing list archive

[PATCH] Further QA consolidation

 

Hi,

Here are a few more patches to finish up consolidating most of the
rest of the QA tools.

1) Adds some very basic dev-docs about the utility programs
2) Housekeeping in qa_utils (hide some code in KI_TEST)
3) qa_shape_factor_refactor is now only SHAPE_POLY_SET tests (the
CPolyline stuff is gone), so move to qa_common where pure geom tests
belong. Kill off this test executable.
4) Reinstate the polygon triangulation util under qa_pcbnew_tools
5) qa_pcbnew_tools: reuse common board reading code (useful when
quickly prototyping with utilities)

The only outstanding broken PCB-related QA things now should be:

* pcb_test_window: what is this for and can it be fixed? Can it be
made into a sub-tool, or does it need its own executable for the
wxApp?

Cheers,

John
From 8efadbfef50cd441f624f0ef3db9e2915924209e Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Thu, 24 Jan 2019 11:33:22 +0000
Subject: [PATCH 1/6] Docs: Describe QA util programs in the testing docs

---
 Documentation/development/testing.md | 35 ++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/Documentation/development/testing.md b/Documentation/development/testing.md
index 6030d986d..5130dad0a 100644
--- a/Documentation/development/testing.md
+++ b/Documentation/development/testing.md
@@ -39,7 +39,7 @@ Common useful patterns:
 * `<test> -t "Utf8/UniIterNull"` runs only a single test in a specific suite.
 * `<test> -l all` adds more verbose debugging to the output.
 * `<test> --list_content` lists the test suites and test cases within the
-    test program. You can use these for arguments to `-l`.
+    test program. You can use these for arguments to `-t`.
 
 You can rebuild just a specific test with CMake to avoid rebuilding
 everything when working on a small area, e.g. `make qa_common`.
@@ -149,6 +149,30 @@ You can run the tests in GDB to trace this:
 If the test segfaults, you will get a familiar backtrace, just like
 if you were running pcbnew under GDB.
 
+# Utility programs {#utility-programs}
+
+KiCad includes some utility programs that can be used for debugging, profiling,
+analysing or developing certain parts of the code without having to invoke the full
+GUI program.
+
+Generally, they are part of the `qa_*_tools` QA executables, each one containing
+the relevant tools for that library. To list the tools in a given program, pass
+the `-l` parameter. Most tools provide help with the `-h` argument.
+To invoke a program:
+
+    qa_<lib>_tools <tool name> [-h] [tool arguments]
+
+Below is a brief outline of some available tools. For full information and command-line
+parameters, refer to the tools' usage test (`-h`).
+
+* `common_tools` (the common library and core functions):
+    * `coroutine`: A simple coroutine example
+    * `io_benchmark`: Show relative speeds of reading files using various IO techniques.
+* `qa_pcbnew_tools` (pcbnew-related functions):
+    * `drc`: Run and benchmark certain DRC functions on a user-provided `.kicad_pcb` files
+    * `pcb_parser`: Parse user-provided `.kicad_pcb` files
+    * `polygon_generator`: Dump polygons found on a PCB to the console
+
 # Fuzz testing {#fuzz-testing}
 
 It is possible to run fuzz testing on some parts of KiCad. To do this for a
@@ -164,12 +188,13 @@ For example, to use the [AFL fuzzing tool][], you will need:
 * To compile this executable with an AFL compiler, to enable the instrumentation
   that allows the fuzzer to detect the fuzzing state.
 
-For example, the `qa_pcb_parse_input` executable can be compiled like this:
+For example, the `qa_pcbnew_tools` executable (which contains `pcb_parser`,
+a fuzz testing tool for `.kicad_pcb` file parsing) can be compiled like this:
 
     mkdir build
     cd build
     cmake -DCMAKE_CXX_COMPILER=/usr/bin/afl-clang-fast++ -DCMAKE_C_COMPILER=/usr/bin/afl-clang-fast ../kicad_src
-    make qa_pcb_parse_input
+    make qa_pcbnew_tools
 
 You may need to disable core dumps and CPU frequency scaling on your system (AFL
 will warn you if you should do this). For example, as root:
@@ -177,9 +202,9 @@ will warn you if you should do this). For example, as root:
     # echo core >/proc/sys/kernel/core_pattern
     # echo performance | tee cpu*/cpufreq/scaling_governor
 
-To fuzz:
+To fuzz, run the executable via `afl-fuzz`:
 
-    afl-fuzz -i fuzzin -o fuzzout -m500 qa/pcb_parse_input/qa_pcb_parse_input
+    afl-fuzz -i fuzzin -o fuzzout -m500 qa/pcbnew_tools/qa_pcbnew_tools pcb_parser
 
 where:
 
-- 
2.20.1

From 0871074a1d09a80a8225ba22178fbc62c4acf1fd Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Thu, 24 Jan 2019 12:12:25 +0000
Subject: [PATCH 2/6] QA: Put UTILITY_PROGRAM in KI_TEST

Also expand some documentation of some other KI_TEST functions.
---
 qa/common_tools/main.cpp                      |  4 +--
 .../tools/coroutines/coroutine_tools.h        |  2 +-
 .../tools/coroutines/coroutines.cpp           |  6 ++--
 .../tools/io_benchmark/io_benchmark.cpp       |  6 ++--
 .../tools/io_benchmark/io_benchmark.h         |  2 +-
 qa/pcbnew_tools/pcbnew_tools.cpp              |  4 +--
 qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp   |  8 ++---
 qa/pcbnew_tools/tools/drc_tool/drc_tool.h     |  2 +-
 .../tools/pcb_parser/pcb_parser_tool.cpp      |  8 ++---
 .../tools/pcb_parser/pcb_parser_tool.h        |  2 +-
 .../polygon_generator/polygon_generator.cpp   |  2 +-
 .../polygon_generator/polygon_generator.h     |  2 +-
 qa/qa_utils/utility_program.cpp               | 14 +++-----
 qa/qa_utils/utility_program.h                 |  5 +++
 .../include/unit_test_utils/unit_test_utils.h | 32 ++++++++++++++++---
 15 files changed, 61 insertions(+), 38 deletions(-)

diff --git a/qa/common_tools/main.cpp b/qa/common_tools/main.cpp
index c6a6a0d96..f42f83d40 100644
--- a/qa/common_tools/main.cpp
+++ b/qa/common_tools/main.cpp
@@ -32,7 +32,7 @@
  * This is a pretty rudimentary way to register, but for a simple purpose,
  * it's effective enough. When you have a new tool, add it to this list.
  */
-const static std::vector<UTILITY_PROGRAM*> known_tools = {
+const static std::vector<KI_TEST::UTILITY_PROGRAM*> known_tools = {
     &coroutine_tool,
     &io_benchmark_tool,
 };
@@ -40,7 +40,7 @@ const static std::vector<UTILITY_PROGRAM*> known_tools = {
 
 int main( int argc, char** argv )
 {
-    COMBINED_UTILITY c_util( known_tools );
+    KI_TEST::COMBINED_UTILITY c_util( known_tools );
 
     return c_util.HandleCommandLine( argc, argv );
 }
\ No newline at end of file
diff --git a/qa/common_tools/tools/coroutines/coroutine_tools.h b/qa/common_tools/tools/coroutines/coroutine_tools.h
index 414d0acbf..89f54501e 100644
--- a/qa/common_tools/tools/coroutines/coroutine_tools.h
+++ b/qa/common_tools/tools/coroutines/coroutine_tools.h
@@ -5,6 +5,6 @@
 #include <utility_program.h>
 
 /// A tool to test a simple coroutine
-extern UTILITY_PROGRAM coroutine_tool;
+extern KI_TEST::UTILITY_PROGRAM coroutine_tool;
 
 #endif
\ No newline at end of file
diff --git a/qa/common_tools/tools/coroutines/coroutines.cpp b/qa/common_tools/tools/coroutines/coroutines.cpp
index 0bea0ce8d..e9b63eac9 100644
--- a/qa/common_tools/tools/coroutines/coroutines.cpp
+++ b/qa/common_tools/tools/coroutines/coroutines.cpp
@@ -114,7 +114,7 @@ static int coroutine_main_func( int argc, char** argv )
     if( cmd_parsed_ok != 0 )
     {
         // Help and invalid input both stop here
-        return ( cmd_parsed_ok == -1 ) ? RET_CODES::OK : RET_CODES::BAD_CMDLINE;
+        return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
     }
 
     long count = 5;
@@ -124,14 +124,14 @@ static int coroutine_main_func( int argc, char** argv )
 
     obj.Run();
 
-    return RET_CODES::OK;
+    return KI_TEST::RET_CODES::OK;
 }
 
 
 /*
  * Define the tool interface
  */
-UTILITY_PROGRAM coroutine_tool = {
+KI_TEST::UTILITY_PROGRAM coroutine_tool = {
     "coroutine",
     "Test a simple coroutine",
     coroutine_main_func,
diff --git a/qa/common_tools/tools/io_benchmark/io_benchmark.cpp b/qa/common_tools/tools/io_benchmark/io_benchmark.cpp
index ce919c01d..a1df3f280 100644
--- a/qa/common_tools/tools/io_benchmark/io_benchmark.cpp
+++ b/qa/common_tools/tools/io_benchmark/io_benchmark.cpp
@@ -388,7 +388,7 @@ int io_benchmark_func( int argc, char* argv[] )
         os << "Usage: " << argv[0] << " <FILE> <REPS> [" << getBenchFlags() << "]\n\n";
         os << "Benchmarks:\n";
         os << getBenchDescriptions();
-        return RET_CODES::BAD_CMDLINE;
+        return KI_TEST::RET_CODES::BAD_CMDLINE;
     }
 
     wxFileName inFile( argv[1] );
@@ -419,11 +419,11 @@ int io_benchmark_func( int argc, char* argv[] )
             << std::endl;;
     }
 
-    return RET_CODES::OK;
+    return KI_TEST::RET_CODES::OK;
 }
 
 
-UTILITY_PROGRAM io_benchmark_tool = {
+KI_TEST::UTILITY_PROGRAM io_benchmark_tool = {
     "io_benchmark",
     "Benchmark various kinds of IO methods",
     io_benchmark_func,
diff --git a/qa/common_tools/tools/io_benchmark/io_benchmark.h b/qa/common_tools/tools/io_benchmark/io_benchmark.h
index e3493a80d..b115ce744 100644
--- a/qa/common_tools/tools/io_benchmark/io_benchmark.h
+++ b/qa/common_tools/tools/io_benchmark/io_benchmark.h
@@ -26,6 +26,6 @@
 
 #include <utility_program.h>
 
-extern UTILITY_PROGRAM io_benchmark_tool;
+extern KI_TEST::UTILITY_PROGRAM io_benchmark_tool;
 
 #endif // IO_BENCHMARK_H
\ No newline at end of file
diff --git a/qa/pcbnew_tools/pcbnew_tools.cpp b/qa/pcbnew_tools/pcbnew_tools.cpp
index dc19d0355..0753e4f8f 100644
--- a/qa/pcbnew_tools/pcbnew_tools.cpp
+++ b/qa/pcbnew_tools/pcbnew_tools.cpp
@@ -33,7 +33,7 @@
  * This is a pretty rudimentary way to register, but for a simple purpose,
  * it's effective enough. When you have a new tool, add it to this list.
  */
-const static std::vector<UTILITY_PROGRAM*> known_tools = {
+const static std::vector<KI_TEST::UTILITY_PROGRAM*> known_tools = {
     &drc_tool,
     &pcb_parser_tool,
     &polygon_generator_tool,
@@ -42,7 +42,7 @@ const static std::vector<UTILITY_PROGRAM*> known_tools = {
 
 int main( int argc, char** argv )
 {
-    COMBINED_UTILITY c_util( known_tools );
+    KI_TEST::COMBINED_UTILITY c_util( known_tools );
 
     return c_util.HandleCommandLine( argc, argv );
 }
\ No newline at end of file
diff --git a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp
index 6af5db505..060da344b 100644
--- a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp
+++ b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp
@@ -304,7 +304,7 @@ static const wxCmdLineEntryDesc g_cmdLineDesc[] = {
  */
 enum PARSER_RET_CODES
 {
-    PARSE_FAILED = RET_CODES::TOOL_SPECIFIC,
+    PARSE_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC,
 };
 
 
@@ -325,7 +325,7 @@ int drc_main_func( int argc, char** argv )
     if( cmd_parsed_ok != 0 )
     {
         // Help and invalid input both stop here
-        return ( cmd_parsed_ok == -1 ) ? RET_CODES::OK : RET_CODES::BAD_CMDLINE;
+        return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
     }
 
     const bool verbose = cl_parser.Found( "verbose" );
@@ -380,14 +380,14 @@ int drc_main_func( int argc, char** argv )
         runner.Execute( *board );
     }
 
-    return RET_CODES::OK;
+    return KI_TEST::RET_CODES::OK;
 }
 
 
 /*
  * Define the tool interface
  */
-UTILITY_PROGRAM drc_tool = {
+KI_TEST::UTILITY_PROGRAM drc_tool = {
     "drc",
     "Run selected DRC function on a PCB",
     drc_main_func,
diff --git a/qa/pcbnew_tools/tools/drc_tool/drc_tool.h b/qa/pcbnew_tools/tools/drc_tool/drc_tool.h
index aa4804994..accb2e97b 100644
--- a/qa/pcbnew_tools/tools/drc_tool/drc_tool.h
+++ b/qa/pcbnew_tools/tools/drc_tool/drc_tool.h
@@ -27,6 +27,6 @@
 #include <utility_program.h>
 
 /// A tool to run DRC tools on KiCad PCBs from the command line
-extern UTILITY_PROGRAM drc_tool;
+extern KI_TEST::UTILITY_PROGRAM drc_tool;
 
 #endif //PCBNEW_TOOLS_DRC_TOOL_H
\ No newline at end of file
diff --git a/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.cpp b/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.cpp
index 3e763a507..e29447bc8 100644
--- a/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.cpp
+++ b/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.cpp
@@ -95,7 +95,7 @@ static const wxCmdLineEntryDesc g_cmdLineDesc[] = {
 
 enum PARSER_RET_CODES
 {
-    PARSE_FAILED = RET_CODES::TOOL_SPECIFIC,
+    PARSE_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC,
 };
 
 
@@ -117,7 +117,7 @@ int pcb_parser_main_func( int argc, char** argv )
     if( cmd_parsed_ok != 0 )
     {
         // Help and invalid input both stop here
-        return ( cmd_parsed_ok == -1 ) ? RET_CODES::OK : RET_CODES::BAD_CMDLINE;
+        return ( cmd_parsed_ok == -1 ) ? KI_TEST::RET_CODES::OK : KI_TEST::RET_CODES::BAD_CMDLINE;
     }
 
     const bool verbose = cl_parser.Found( "verbose" );
@@ -157,14 +157,14 @@ int pcb_parser_main_func( int argc, char** argv )
     if( !ok )
         return PARSER_RET_CODES::PARSE_FAILED;
 
-    return RET_CODES::OK;
+    return KI_TEST::RET_CODES::OK;
 }
 
 
 /*
  * Define the tool interface
  */
-UTILITY_PROGRAM pcb_parser_tool = {
+KI_TEST::UTILITY_PROGRAM pcb_parser_tool = {
     "pcb_parser",
     "Parse a KiCad PCB file",
     pcb_parser_main_func,
diff --git a/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.h b/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.h
index ddab182d7..cfbe4fb57 100644
--- a/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.h
+++ b/qa/pcbnew_tools/tools/pcb_parser/pcb_parser_tool.h
@@ -27,6 +27,6 @@
 #include <utility_program.h>
 
 /// A tool to parse kicad PCBs from the command line
-extern UTILITY_PROGRAM pcb_parser_tool;
+extern KI_TEST::UTILITY_PROGRAM pcb_parser_tool;
 
 #endif //PCBNEW_TOOLS_PCB_PARSER_UTILITY_H
\ No newline at end of file
diff --git a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp
index 09af99144..593314392 100644
--- a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp
+++ b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp
@@ -118,7 +118,7 @@ int polygon_gererator_main( int argc, char* argv[] )
 /*
  * Define the tool interface
  */
-UTILITY_PROGRAM polygon_generator_tool = {
+KI_TEST::UTILITY_PROGRAM polygon_generator_tool = {
     "polygon_generator",
     "Dump board geometry as a set of polygons",
     polygon_gererator_main,
diff --git a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.h b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.h
index a1faee298..bab141224 100644
--- a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.h
+++ b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.h
@@ -27,6 +27,6 @@
 #include <utility_program.h>
 
 /// A tool to parse kicad PCBs from the command line
-extern UTILITY_PROGRAM polygon_generator_tool;
+extern KI_TEST::UTILITY_PROGRAM polygon_generator_tool;
 
 #endif //PCBNEW_TOOLS_POLYGON_GENERATOR_UTILITY_H
\ No newline at end of file
diff --git a/qa/qa_utils/utility_program.cpp b/qa/qa_utils/utility_program.cpp
index 0da346e4d..39457c44a 100644
--- a/qa/qa_utils/utility_program.cpp
+++ b/qa/qa_utils/utility_program.cpp
@@ -24,15 +24,14 @@
 
 #include <wx/msgout.h>
 
+namespace KI_TEST
+{
 
 COMBINED_UTILITY::COMBINED_UTILITY( const UTIL_LIST& aSubUtils ) : m_subUtils( aSubUtils )
 {
 }
 
 
-/**
- * Print the names and descriptions of the registered tools
- */
 void COMBINED_UTILITY::showSubUtilityList( std::ostream& os ) const
 {
     for( const auto& tool : m_subUtils )
@@ -42,11 +41,6 @@ void COMBINED_UTILITY::showSubUtilityList( std::ostream& os ) const
 }
 
 
-/**
- * Get the utility program that matches a tool name
- * @param  aName the name to look for
- * @return       the tool function
- */
 UTILITY_PROGRAM::FUNC* COMBINED_UTILITY::findSubUtility( const std::string& aName ) const
 {
     for( const auto& tool : m_subUtils )
@@ -112,4 +106,6 @@ int COMBINED_UTILITY::HandleCommandLine( int argc, char** argv ) const
 
     // pass on the rest of the commands
     return ( *func )( argc - 1, argv + 1 );
-}
\ No newline at end of file
+}
+
+} // namespace KI_TEST
\ No newline at end of file
diff --git a/qa/qa_utils/utility_program.h b/qa/qa_utils/utility_program.h
index b862bbe62..dec141768 100644
--- a/qa/qa_utils/utility_program.h
+++ b/qa/qa_utils/utility_program.h
@@ -29,6 +29,9 @@
 #include <string>
 #include <vector>
 
+namespace KI_TEST
+{
+
 /**
  * Return codes for tools
  */
@@ -127,4 +130,6 @@ private:
     const UTIL_LIST& m_subUtils;
 };
 
+} // namespace KI_TEST
+
 #endif // UTILITY_PROGRAM_H
\ No newline at end of file
diff --git a/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h b/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h
index e6523ea96..e11f33bf5 100644
--- a/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h
+++ b/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h
@@ -80,6 +80,29 @@
 
 namespace KI_TEST
 {
+
+template <typename EXP_CONT> using EXP_OBJ = typename EXP_CONT::value_type;
+template <typename FOUND_CONT> using FOUND_OBJ = typename FOUND_CONT::value_type;
+
+/**
+ * A match predicate: check that a "found" object is equivalent to or represents
+ * an "expected" object, perhaps of a different type.
+ *
+ * Exactly what "equivalent to" means depends heavily on the context and what
+ * is care about. For example, if you only care about a #MODULE's refdes,
+ * std::string is sufficient to indicate a "match".
+ *
+ * This can be used, for example, for checking a set of results without having
+ * to instantiate a full result object for checking by equality.
+ *
+ * @tparam EXP_OBJ      the "expected" object type
+ * @tparam FOUND_OBJ    the "found" object type
+ *
+ * @return true if the "found" object represents the "expected" object
+ */
+template <typename EXP_OBJ, typename FOUND_OBJ>
+using MATCH_PRED = std::function<bool( const EXP_OBJ&, const FOUND_OBJ& )>;
+
 /**
  * Check that a container of "found" objects matches a container of "expected"
  * objects. This means that:
@@ -91,7 +114,7 @@ namespace KI_TEST
  * and a function to check if a given "found" object corresponds to a given
  * "expected object". Conditions:
  *
- * * The expected object type needs operator<<
+ * * The expected object type needs `operator<<` (for logging)
  * * The expected object container does not contain multiple references to the
  *   same object.
  * * Identical values are also can't be present as the predicate can't tell which
@@ -105,16 +128,15 @@ namespace KI_TEST
  * lists and checking element-by-element matches. However, it can tell you
  * exactly which objects are problematic, as well as a simple go/no-go.
  *
+ * When you have two containers of identical types (or you have a suitable
+ * `operator==`) and ordering is important, you can use `BOOST_CHECK_EQUAL_COLLECTIONS`
+ *
  *@param aExpected  a container of "expected" items, usually from a test case
  *@param aMatched   a container of "found" items, usually the result of some
  *                  routine under test
  *@param aMatchPredicate a predicate that determines if a given "found" object
  *                  matches a given "expected" object.
  */
-template <typename EXP_CONT> using EXP_OBJ = typename EXP_CONT::value_type;
-template <typename FOUND_CONT> using FOUND_OBJ = typename FOUND_CONT::value_type;
-template <typename EXP_OBJ, typename FOUND_OBJ>
-using MATCH_PRED = std::function<bool( const EXP_OBJ&, const FOUND_OBJ& )>;
 template <typename EXP_CONT, typename FOUND_CONT, typename MATCH_PRED>
 void CheckUnorderedMatches(
         const EXP_CONT& aExpected, const FOUND_CONT& aFound, MATCH_PRED aMatchPredicate )
-- 
2.20.1

From 76cac5f399a4d7db96ca0a5f790dceaec4e7ffb0 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Thu, 24 Jan 2019 14:56:55 +0000
Subject: [PATCH 5/6] QA: Centralise BOARD reading functions in pcbnew_utils

Several pcbnew_tools utilities read a file from the command line.
Instead of replicating this code, centralise the code in
qa_pcbnew_utils, which allows simpler reuse.

THe utilities are:

* polygon_triangulation
* polygon_generator
* drc_tool

pcb_parser keeps its own function, as that is the focus of the tool,
and its likely to have its own instrumention.

This also adds the ability to read from stdin for the above tools,
which means fuzz testers could theoretically work with them, and it
also can make life easier if you can pipe a board to the executable
directly.
---
 qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp   | 62 ++-----------------
 .../polygon_generator/polygon_generator.cpp   | 46 ++++++--------
 .../polygon_triangulation.cpp                 | 43 ++++---------
 qa/pcbnew_utils/CMakeLists.txt                |  4 +-
 qa/pcbnew_utils/board_file_utils.cpp          | 48 ++++++++++++++
 .../include/pcbnew_utils/board_file_utils.h   | 35 ++++++++++-
 6 files changed, 120 insertions(+), 118 deletions(-)

diff --git a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp
index 060da344b..28b3acd93 100644
--- a/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp
+++ b/qa/pcbnew_tools/tools/drc_tool/drc_tool.cpp
@@ -30,12 +30,7 @@
 
 #include <wx/cmdline.h>
 
-// Parsing
-#include <class_board.h>
-#include <class_board_item.h>
-#include <kicad_plugin.h>
-#include <pcb_parser.h>
-#include <richio.h>
+#include <pcbnew_utils/board_file_utils.h>
 
 // DRC
 #include <drc/courtyard_overlap.h>
@@ -45,36 +40,6 @@
 #include <stdstream_line_reader.h>
 
 
-/**
- * Parse a PCB from the given stream
- *
- * @param aStream the input stream to read from
- */
-std::unique_ptr<BOARD> parse( std::istream& aStream )
-{
-    // Take input from stdin
-    STDISTREAM_LINE_READER reader;
-    reader.SetStream( aStream );
-
-    PCB_PARSER parser;
-
-    parser.SetLineReader( &reader );
-
-    std::unique_ptr<BOARD> board;
-
-    try
-    {
-        board.reset( dynamic_cast<BOARD*>( parser.Parse() ) );
-    }
-    catch( const IO_ERROR& parse_error )
-    {
-        std::cerr << parse_error.Problem() << std::endl;
-        std::cerr << parse_error.Where() << std::endl;
-    }
-
-    return board;
-}
-
 using DRC_DURATION = std::chrono::microseconds;
 
 /**
@@ -330,31 +295,14 @@ int drc_main_func( int argc, char** argv )
 
     const bool verbose = cl_parser.Found( "verbose" );
 
-    const auto file_count = cl_parser.GetParamCount();
-
-    std::unique_ptr<BOARD> board;
+    std::string filename;
 
-    if( file_count == 0 )
+    if( cl_parser.GetParamCount() )
     {
-        // Parse the file provided on stdin - used by AFL to drive the
-        // program
-        // while (__AFL_LOOP(2))
-        {
-            board = parse( std::cin );
-        }
+        filename = cl_parser.GetParam( 0 ).ToStdString();
     }
-    else
-    {
-        const auto filename = cl_parser.GetParam( 0 ).ToStdString();
-
-        if( verbose )
-            std::cout << "Parsing: " << filename << std::endl;
 
-        std::ifstream fin;
-        fin.open( filename );
-
-        board = parse( fin );
-    }
+    std::unique_ptr<BOARD> board = KI_TEST::ReadBoardFromFileOrStream( filename );
 
     if( !board )
         return PARSER_RET_CODES::PARSE_FAILED;
diff --git a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp
index 593314392..8aba10b90 100644
--- a/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp
+++ b/qa/pcbnew_tools/tools/polygon_generator/polygon_generator.cpp
@@ -29,8 +29,7 @@
 #include <geometry/shape_line_chain.h>
 #include <geometry/shape_poly_set.h>
 
-#include <io_mgr.h>
-#include <kicad_plugin.h>
+#include <pcbnew_utils/board_file_utils.h>
 
 #include <class_board.h>
 #include <class_drawsegment.h>
@@ -39,26 +38,6 @@
 #include <class_track.h>
 #include <class_zone.h>
 
-BOARD* loadBoard( const std::string& filename )
-{
-    PLUGIN::RELEASER pi( new PCB_IO );
-    BOARD*           brd = nullptr;
-
-    try
-    {
-        brd = pi->Load( wxString( filename.c_str() ), NULL, NULL );
-    }
-    catch( const IO_ERROR& ioe )
-    {
-        wxString msg = wxString::Format( _( "Error loading board.\n%s" ), ioe.Problem() );
-
-        printf( "%s\n", (const char*) msg.mb_str() );
-        return nullptr;
-    }
-
-    return brd;
-}
-
 
 void process( const BOARD_CONNECTED_ITEM* item, int net )
 {
@@ -79,19 +58,32 @@ void process( const BOARD_CONNECTED_ITEM* item, int net )
 }
 
 
+enum POLY_GEN_RET_CODES
+{
+    LOAD_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC,
+};
+
+
 int polygon_gererator_main( int argc, char* argv[] )
 {
     if( argc < 2 )
     {
         printf( "A sample tool for dumping board geometry as a set of polygons.\n" );
-        printf( "usage : %s board_file.kicad_pcb\n\n", argv[0] );
-        return -1;
+        printf( "Usage : %s board_file.kicad_pcb\n\n", argv[0] );
+        return KI_TEST::RET_CODES::BAD_CMDLINE;
     }
 
-    std::unique_ptr<BOARD> brd( loadBoard( argv[1] ) );
+    std::string filename;
+
+    if( argc > 1 )
+        filename = argv[1];
+
+    auto brd = KI_TEST::ReadBoardFromFileOrStream( filename );
 
     if( !brd )
-        return -1;
+    {
+        return POLY_GEN_RET_CODES::LOAD_FAILED;
+    }
 
     for( unsigned net = 0; net < brd->GetNetCount(); net++ )
     {
@@ -112,7 +104,7 @@ int polygon_gererator_main( int argc, char* argv[] )
         printf( "endnet\n" );
     }
 
-    return 0;
+    return KI_TEST::RET_CODES::OK;
 }
 
 /*
diff --git a/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
index d10af9a6b..7f9924393 100644
--- a/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
+++ b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
@@ -24,11 +24,10 @@
 
 #include "polygon_triangulation.h"
 
-#include <geometry/shape_poly_set.h>
 #include <geometry/shape_line_chain.h>
+#include <geometry/shape_poly_set.h>
 
-#include <io_mgr.h>
-#include <kicad_plugin.h>
+#include <pcbnew_utils/board_file_utils.h>
 
 #include <class_board.h>
 #include <class_zone.h>
@@ -200,26 +199,6 @@ aResult->clear();
         std::swap( (*aResult) [0], (*aResult)[outline] );
 }
 
-BOARD* loadBoardTri( const std::string& filename )
-{
-    PLUGIN::RELEASER pi( new PCB_IO );
-    BOARD* brd = nullptr;
-
-    try
-    {
-        brd = pi->Load( wxString( filename.c_str() ), NULL, NULL );
-    }
-    catch( const IO_ERROR& ioe )
-    {
-        wxString msg = wxString::Format( _( "Error loading board.\n%s" ),
-                ioe.Problem() );
-
-        printf( "%s\n", (const char*) msg.mb_str() );
-        return nullptr;
-    }
-
-    return brd;
-}
 
 enum POLY_TRI_RET_CODES
 {
@@ -229,7 +208,12 @@ enum POLY_TRI_RET_CODES
 
 int polygon_triangulation_main( int argc, char *argv[] )
 {
-    auto brd = loadBoardTri( argc > 1 ? argv[1] : "../../../../tests/dp.kicad_pcb" );
+    std::string filename;
+
+    if( argc > 1 )
+        filename = argv[1];
+
+    auto brd = KI_TEST::ReadBoardFromFileOrStream( filename );
 
     if( !brd )
         return POLY_TRI_RET_CODES::LOAD_FAILED;
@@ -244,8 +228,7 @@ int polygon_triangulation_main( int argc, char *argv[] )
     size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
     for( size_t ii = 0; ii < parallelThreadCount; ++ii )
     {
-        std::thread t = std::thread( [brd, &zonesToTriangulate, &threadsFinished] ()
-        {
+        std::thread t = std::thread( [&brd, &zonesToTriangulate, &threadsFinished]() {
             for( size_t areaId = zonesToTriangulate.fetch_add( 1 );
                         areaId < static_cast<size_t>( brd->GetAreaCount() );
                         areaId = zonesToTriangulate.fetch_add( 1 ) )
@@ -257,7 +240,7 @@ int polygon_triangulation_main( int argc, char *argv[] )
 
                 (void) poly;
                 printf("zone %zu/%d\n", ( areaId + 1 ), brd->GetAreaCount() );
-        #if 0
+#if 0
                 PROF_COUNTER unfrac("unfrac");
                 poly.Unfracture( SHAPE_POLY_SET::PM_FAST );
                 unfrac.Show();
@@ -269,7 +252,7 @@ int polygon_triangulation_main( int argc, char *argv[] )
                     poly.triangulatePoly( &poly.Polygon(i) );
                 }
                 triangulate.Show();
-        #endif
+#endif
             }
 
             threadsFinished++;
@@ -281,13 +264,9 @@ int polygon_triangulation_main( int argc, char *argv[] )
     while( threadsFinished < parallelThreadCount )
         std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
 
-
     cnt.Show();
 
-    delete brd;
-
     return KI_TEST::RET_CODES::OK;
-
 }
 
 /*
diff --git a/qa/pcbnew_utils/CMakeLists.txt b/qa/pcbnew_utils/CMakeLists.txt
index f67eb7011..e2316d2ef 100644
--- a/qa/pcbnew_utils/CMakeLists.txt
+++ b/qa/pcbnew_utils/CMakeLists.txt
@@ -54,7 +54,9 @@ target_include_directories( qa_pcbnew_utils PUBLIC
     ${INC_AFTER}
 )
 
-# target_link_libraries( qa_pcbnew_utils PUBLIC
+target_link_libraries( qa_pcbnew_utils PUBLIC
+    qa_utils
+)
 #     3d-viewer
 #     connectivity
 #     pcbcommon
diff --git a/qa/pcbnew_utils/board_file_utils.cpp b/qa/pcbnew_utils/board_file_utils.cpp
index c278c22ed..d4969ae91 100644
--- a/qa/pcbnew_utils/board_file_utils.cpp
+++ b/qa/pcbnew_utils/board_file_utils.cpp
@@ -30,6 +30,8 @@
 
 #include <class_board.h>
 
+#include <stdstream_line_reader.h>
+
 namespace KI_TEST
 {
 
@@ -50,4 +52,50 @@ std::unique_ptr<BOARD_ITEM> ReadBoardItemFromFile( const std::string& aFilename
     return std::unique_ptr<BOARD_ITEM>( parser.Parse() );
 }
 
+
+std::unique_ptr<BOARD_ITEM> ReadBoardItemFromStream( std::istream& aStream )
+{
+    // Take input from stdin
+    STDISTREAM_LINE_READER reader;
+    reader.SetStream( aStream );
+
+    PCB_PARSER parser;
+
+    parser.SetLineReader( &reader );
+
+    std::unique_ptr<BOARD_ITEM> board;
+
+    try
+    {
+        board.reset( parser.Parse() );
+    }
+    catch( const IO_ERROR& parse_error )
+    {
+        std::cerr << parse_error.Problem() << std::endl;
+        std::cerr << parse_error.Where() << std::endl;
+    }
+
+    return board;
+}
+
+std::unique_ptr<BOARD> ReadBoardFromFileOrStream(
+        const std::string& aFilename, std::istream& aFallback )
+{
+    std::istream* in_stream = nullptr;
+    std::ifstream file_stream;
+
+    if( aFilename.empty() )
+    {
+        // no file, read stdin
+        in_stream = &aFallback;
+    }
+    else
+    {
+        file_stream.open( aFilename );
+        in_stream = &file_stream;
+    }
+
+    return ReadItemFromStream<BOARD>( *in_stream );
+}
+
 } // namespace KI_TEST
\ No newline at end of file
diff --git a/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h b/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h
index 8543487fd..4f39b9fbd 100644
--- a/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h
+++ b/qa/pcbnew_utils/include/pcbnew_utils/board_file_utils.h
@@ -25,6 +25,7 @@
 #ifndef QA_PCBNEW_UTILS_BOARD_FILE_UTILS__H
 #define QA_PCBNEW_UTILS_BOARD_FILE_UTILS__H
 
+#include <iostream>
 #include <memory>
 #include <string>
 
@@ -60,7 +61,39 @@ void DumpBoardToFile( BOARD& aBoard, const std::string& aFilename );
  * @param aFilename   the file to read in
  * @returns           a new #BOARD_ITEM, which is nullptr if the read or parse failed.
  */
-std::unique_ptr<BOARD_ITEM> ReadBoardItemFromFile( const std::string& aFilename );
+std::unique_ptr<BOARD_ITEM> ReadBoardItemFromStream( std::istream& aStream );
+
+/**
+ * Read a specific kind of #BOARD_ITEM from a stream
+ *
+ * @tparam ITEM the item type to return (probably a #MODULE or #BOARD)
+ * @param aStream the stream to read from.
+ */
+template <typename ITEM> std::unique_ptr<ITEM> ReadItemFromStream( std::istream& aStream )
+{
+    auto                  bi_ptr = ReadBoardItemFromStream( aStream );
+    std::unique_ptr<ITEM> downcast_ptr;
+
+    // if it's the right type, downcast and "steal" (and we'll return ownership)
+    ITEM* const tmp = dynamic_cast<ITEM*>( bi_ptr.get() );
+    if( tmp != nullptr )
+    {
+        bi_ptr.release();
+        downcast_ptr.reset( tmp );
+    }
+
+    return downcast_ptr;
+}
+
+/**
+ * Read a board from a file, or another stream, as appropriate
+ *
+ * @param aFilename The file to read, or the fallback if empty
+ * @param aFallback: the fallback stream
+ * @return a #BOARD, if successful
+ */
+std::unique_ptr<BOARD> ReadBoardFromFileOrStream(
+        const std::string& aFilename, std::istream& aFallback = std::cin );
 
 } // namespace KI_TEST
 
-- 
2.20.1

From f9d065f2928469f9637fe403cb34d7637fa6e45d Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Thu, 24 Jan 2019 13:19:23 +0000
Subject: [PATCH 3/6] QA: Move contents qa_shape_poly_set_refactor to qa_common

The "refactor" element of qa_shape_poly_set_refactor has been
previously removed, so these tests are now just regular tests on
libcommon classes. These can therefore be moved to qa_common
and the qa_shape_poly_set_refactor unit test suit can finally be
totally removed.
---
 qa/CMakeLists.txt                             |   1 -
 qa/common/CMakeLists.txt                      |   5 +-
 .../geometry}/fixtures_geometry.h             | 143 ++++--------------
 .../geometry}/test_segment.cpp                |  32 ++--
 .../test_shape_poly_set_collision.cpp}        |  73 +++++++--
 .../test_shape_poly_set_iterator.cpp}         |  86 +++++++++--
 qa/shape_poly_set_refactor/CMakeLists.txt     |  59 --------
 qa/shape_poly_set_refactor/test_module.cpp    |  32 ----
 8 files changed, 174 insertions(+), 257 deletions(-)
 rename qa/{data => common/geometry}/fixtures_geometry.h (51%)
 rename qa/{shape_poly_set_refactor => common/geometry}/test_segment.cpp (66%)
 rename qa/{shape_poly_set_refactor/test_collision.cpp => common/geometry/test_shape_poly_set_collision.cpp} (70%)
 rename qa/{shape_poly_set_refactor/test_iterator.cpp => common/geometry/test_shape_poly_set_iterator.cpp} (60%)
 delete mode 100644 qa/shape_poly_set_refactor/CMakeLists.txt
 delete mode 100644 qa/shape_poly_set_refactor/test_module.cpp

diff --git a/qa/CMakeLists.txt b/qa/CMakeLists.txt
index 179962ebe..6502a461c 100644
--- a/qa/CMakeLists.txt
+++ b/qa/CMakeLists.txt
@@ -21,7 +21,6 @@ add_subdirectory( unit_test_utils )
 add_subdirectory( common )
 add_subdirectory( pcbnew )
 add_subdirectory( eeschema )
-add_subdirectory( shape_poly_set_refactor )
 
 # Utility/debugging/profiling programs
 add_subdirectory( common_tools )
diff --git a/qa/common/CMakeLists.txt b/qa/common/CMakeLists.txt
index 8e2f89209..5b105f139 100644
--- a/qa/common/CMakeLists.txt
+++ b/qa/common/CMakeLists.txt
@@ -47,12 +47,15 @@ set( common_srcs
     libeval/test_numeric_evaluator.cpp
 
     geometry/test_fillet.cpp
+    geometry/test_segment.cpp
     geometry/test_shape_arc.cpp
+    geometry/test_shape_poly_set_collision.cpp
+    geometry/test_shape_poly_set_iterator.cpp
 
     view/test_zoom_controller.cpp
 )
 
-set( common_libs 
+set( common_libs
     common
     legacy_gal
     polygon
diff --git a/qa/data/fixtures_geometry.h b/qa/common/geometry/fixtures_geometry.h
similarity index 51%
rename from qa/data/fixtures_geometry.h
rename to qa/common/geometry/fixtures_geometry.h
index b7c97c001..9bf97f291 100644
--- a/qa/data/fixtures_geometry.h
+++ b/qa/common/geometry/fixtures_geometry.h
@@ -22,14 +22,17 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
-#ifndef __FIXTURES_H
-#define __FIXTURES_H
+#ifndef QA_COMMON_GEOMETRY_FIXTURES_GEOEMETRY__H
+#define QA_COMMON_GEOMETRY_FIXTURES_GEOEMETRY__H
 
-#include <geometry/shape_poly_set.h>
 #include <geometry/shape_line_chain.h>
+#include <geometry/shape_poly_set.h>
+
+namespace KI_TEST
+{
 
 /**
- * Common data for the tests:
+ * Common data for some of the #SHAPE_POLY_SET tests:
  *      1. holeyPolySet: A polyset containing one single squared outline with two holes: a
  *      non-convex pentagon and a triangle.
  *      2.solidPolySet: A polyset with three empty outlines and no holes.
@@ -47,7 +50,7 @@ struct CommonTestData
     // Vectors containing the information with which the polygons are populated.
     std::vector<VECTOR2I> uniquePoints;
     std::vector<VECTOR2I> holeyPoints;
-    std::vector<SEG> holeySegments;
+    std::vector<SEG>      holeySegments;
 
     /**
      * Constructor.
@@ -60,22 +63,22 @@ struct CommonTestData
         // Populate the holey polygon set points with 12 points
 
         // Square
-        holeyPoints.push_back( VECTOR2I( 100,100 ) );
-        holeyPoints.push_back( VECTOR2I( 0,100 ) );
-        holeyPoints.push_back( VECTOR2I( 0,0 ) );
-        holeyPoints.push_back( VECTOR2I( 100,0 ) );
+        holeyPoints.push_back( VECTOR2I( 100, 100 ) );
+        holeyPoints.push_back( VECTOR2I( 0, 100 ) );
+        holeyPoints.push_back( VECTOR2I( 0, 0 ) );
+        holeyPoints.push_back( VECTOR2I( 100, 0 ) );
 
         // Pentagon
-        holeyPoints.push_back( VECTOR2I( 10,10 ) );
-        holeyPoints.push_back( VECTOR2I( 10,20 ) );
-        holeyPoints.push_back( VECTOR2I( 15,15 ) );
-        holeyPoints.push_back( VECTOR2I( 20,20 ) );
-        holeyPoints.push_back( VECTOR2I( 20,10 ) );
+        holeyPoints.push_back( VECTOR2I( 10, 10 ) );
+        holeyPoints.push_back( VECTOR2I( 10, 20 ) );
+        holeyPoints.push_back( VECTOR2I( 15, 15 ) );
+        holeyPoints.push_back( VECTOR2I( 20, 20 ) );
+        holeyPoints.push_back( VECTOR2I( 20, 10 ) );
 
         // Triangle
-        holeyPoints.push_back( VECTOR2I( 40,10 ) );
-        holeyPoints.push_back( VECTOR2I( 40,20 ) );
-        holeyPoints.push_back( VECTOR2I( 60,10 ) );
+        holeyPoints.push_back( VECTOR2I( 40, 10 ) );
+        holeyPoints.push_back( VECTOR2I( 40, 20 ) );
+        holeyPoints.push_back( VECTOR2I( 60, 10 ) );
 
         // Save the segments of the holeyPolySet.
         holeySegments.push_back( SEG( holeyPoints[0], holeyPoints[1] ) );
@@ -91,7 +94,7 @@ struct CommonTestData
         holeySegments.push_back( SEG( holeyPoints[8], holeyPoints[4] ) );
 
         // Triangle segments
-        holeySegments.push_back( SEG( holeyPoints[ 9], holeyPoints[10] ) );
+        holeySegments.push_back( SEG( holeyPoints[9], holeyPoints[10] ) );
         holeySegments.push_back( SEG( holeyPoints[10], holeyPoints[11] ) );
         holeySegments.push_back( SEG( holeyPoints[11], holeyPoints[9] ) );
 
@@ -101,7 +104,7 @@ struct CommonTestData
         // Create a polygon set with a unique vertex
         polyLine.Append( uniquePoints[0] );
         polyLine.SetClosed( true );
-        uniqueVertexPolySet.AddOutline(polyLine);
+        uniqueVertexPolySet.AddOutline( polyLine );
 
         // Create a polygon set without holes
         solidPolySet.NewOutline();
@@ -118,7 +121,7 @@ struct CommonTestData
 
         polyLine.SetClosed( true );
 
-        holeyPolySet.AddOutline(polyLine);
+        holeyPolySet.AddOutline( polyLine );
 
         // Adds a new hole (a pentagon)
         for( int i = 4; i < 9; i++ )
@@ -137,105 +140,11 @@ struct CommonTestData
         holeyPolySet.AddHole( hole );
     }
 
-    ~CommonTestData(){}
-};
-
-
-/**
- * Fixture for the Collision test suite. It contains an instance of the common data and two
- * vectors containing colliding and non-colliding points.
- */
-struct CollisionFixture {
-    // Structure to store the common data.
-    struct CommonTestData common;
-
-    // Vectors containing colliding and non-colliding points
-    std::vector<VECTOR2I> collidingPoints, nonCollidingPoints;
-
-    /**
-    * Constructor
-    */
-    CollisionFixture()
+    ~CommonTestData()
     {
-        // Create points colliding with the poly set.
-
-        // Inside the polygon
-        collidingPoints.push_back( VECTOR2I( 10,90 ) );
-
-        // Inside the polygon, but on a re-entrant angle of a hole
-        collidingPoints.push_back( VECTOR2I( 15,16 ) );
-
-        // On a hole edge => inside the polygon
-        collidingPoints.push_back( VECTOR2I( 40,25 ) );
-
-        // On the outline edge => inside the polygon
-        collidingPoints.push_back( VECTOR2I( 0,10 ) );
-
-        // Create points not colliding with the poly set.
-
-        // Completely outside of the polygon
-        nonCollidingPoints.push_back( VECTOR2I( 200,200 ) );
-
-        // Inside the outline and inside a hole => outside the polygon
-        nonCollidingPoints.push_back( VECTOR2I( 15,12 ) );
     }
-
-    ~CollisionFixture(){}
 };
 
-/**
-* Fixture for the Iterator test suite. It contains an instance of the common data, three polysets with null segments and a vector containing their points.
-*/
-struct IteratorFixture {
-    // Structure to store the common data.
-    struct CommonTestData common;
-
-    // Polygons to test whether the RemoveNullSegments method works
-    SHAPE_POLY_SET lastNullSegmentPolySet;
-    SHAPE_POLY_SET firstNullSegmentPolySet;
-    SHAPE_POLY_SET insideNullSegmentPolySet;
-
-    // Null segments points
-    std::vector<VECTOR2I> nullPoints;
-
-    IteratorFixture()
-    {
-        nullPoints.push_back( VECTOR2I( 100,100 ) );
-        nullPoints.push_back( VECTOR2I(   0,100 ) );
-        nullPoints.push_back( VECTOR2I(   0,  0 ) );
-
-        // Create a polygon with its last segment null
-        SHAPE_LINE_CHAIN polyLine;
-        polyLine.Append( nullPoints[0] );
-        polyLine.Append( nullPoints[1] );
-        polyLine.Append( nullPoints[2] );
-        polyLine.Append( nullPoints[2], true );
-        polyLine.SetClosed( true );
-
-        lastNullSegmentPolySet.AddOutline(polyLine);
-
-        // Create a polygon with its first segment null
-        polyLine.Clear();
-        polyLine.Append( nullPoints[0] );
-        polyLine.Append( nullPoints[0], true );
-        polyLine.Append( nullPoints[1] );
-        polyLine.Append( nullPoints[2] );
-        polyLine.SetClosed( true );
-
-        firstNullSegmentPolySet.AddOutline(polyLine);
-
-        // Create a polygon with an inside segment null
-        polyLine.Clear();
-        polyLine.Append( nullPoints[0] );
-        polyLine.Append( nullPoints[1] );
-        polyLine.Append( nullPoints[1], true );
-        polyLine.Append( nullPoints[2] );
-        polyLine.SetClosed( true );
-
-        insideNullSegmentPolySet.AddOutline(polyLine);
-    }
-
-    ~IteratorFixture(){}
-};
+} // namespace KI_TEST
 
-#endif //__FIXTURES_H
+#endif // QA_COMMON_GEOMETRY_FIXTURES_GEOEMETRY__H
diff --git a/qa/shape_poly_set_refactor/test_segment.cpp b/qa/common/geometry/test_segment.cpp
similarity index 66%
rename from qa/shape_poly_set_refactor/test_segment.cpp
rename to qa/common/geometry/test_segment.cpp
index 30cbc2dd2..679b1f4b7 100644
--- a/qa/shape_poly_set_refactor/test_segment.cpp
+++ b/qa/common/geometry/test_segment.cpp
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2017 CERN
  * @author Alejandro García Montoro <alejandro.garciamontoro@xxxxxxxxx>
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -22,42 +23,35 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
+#include <unit_test_utils/unit_test_utils.h>
+
 #include <geometry/seg.h>
 
-#include <qa/data/fixtures_geometry.h>
 
-/**
- * Declares the IteratorFixture as the boost test suite fixture.
- */
-BOOST_FIXTURE_TEST_SUITE( SegmentReference, CommonTestData )
+BOOST_AUTO_TEST_SUITE( Segment )
 
 /**
- * Checks whether the construction of a segment referencing external points works.
+ * Checks whether the construction of a segment referencing external points works
+ * and that the endpoints can be modified as normal points.
  */
-BOOST_AUTO_TEST_CASE( SegmentReference )
+BOOST_AUTO_TEST_CASE( EndpointCtorMod )
 {
-    VECTOR2I pointA( 10, 20 );
-    VECTOR2I pointB( 100, 200 );
+    const VECTOR2I pointA{ 10, 20 };
+    const VECTOR2I pointB{ 100, 200 };
 
     // Build a segment referencing the previous points
     SEG segment( pointA, pointB );
 
-    BOOST_CHECK_EQUAL( pointA, VECTOR2I( 10, 20) );
-    BOOST_CHECK_EQUAL( pointB, VECTOR2I( 100, 200) );
+    BOOST_CHECK_EQUAL( pointA, VECTOR2I( 10, 20 ) );
+    BOOST_CHECK_EQUAL( pointB, VECTOR2I( 100, 200 ) );
 
     // Modify the ends of the segments
     segment.A += VECTOR2I( 10, 10 );
     segment.B += VECTOR2I( 100, 100 );
 
-    // Check that the original points are not modified
-    BOOST_CHECK_EQUAL( pointA, VECTOR2I( 10, 20) );
-    BOOST_CHECK_EQUAL( pointB, VECTOR2I( 100, 200) );
-
     // Check that the ends in segment are modified
-    BOOST_CHECK_EQUAL( segment.A, VECTOR2I( 20, 30) );
-    BOOST_CHECK_EQUAL( segment.B, VECTOR2I( 200, 300) );
+    BOOST_CHECK_EQUAL( segment.A, VECTOR2I( 20, 30 ) );
+    BOOST_CHECK_EQUAL( segment.B, VECTOR2I( 200, 300 ) );
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/qa/shape_poly_set_refactor/test_collision.cpp b/qa/common/geometry/test_shape_poly_set_collision.cpp
similarity index 70%
rename from qa/shape_poly_set_refactor/test_collision.cpp
rename to qa/common/geometry/test_shape_poly_set_collision.cpp
index 850b0d988..46de3db4b 100644
--- a/qa/shape_poly_set_refactor/test_collision.cpp
+++ b/qa/common/geometry/test_shape_poly_set_collision.cpp
@@ -22,12 +22,57 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-#include <geometry/shape_poly_set.h>
+#include <unit_test_utils/unit_test_utils.h>
+
 #include <geometry/shape_line_chain.h>
+#include <geometry/shape_poly_set.h>
+
+#include "fixtures_geometry.h"
+
+/**
+ * Fixture for the Collision test suite. It contains an instance of the common data and two
+ * vectors containing colliding and non-colliding points.
+ */
+struct CollisionFixture
+{
+    // Structure to store the common data.
+    struct KI_TEST::CommonTestData common;
+
+    // Vectors containing colliding and non-colliding points
+    std::vector<VECTOR2I> collidingPoints, nonCollidingPoints;
+
+    /**
+    * Constructor
+    */
+    CollisionFixture()
+    {
+        // Create points colliding with the poly set.
 
-#include <qa/data/fixtures_geometry.h>
+        // Inside the polygon
+        collidingPoints.push_back( VECTOR2I( 10, 90 ) );
+
+        // Inside the polygon, but on a re-entrant angle of a hole
+        collidingPoints.push_back( VECTOR2I( 15, 16 ) );
+
+        // On a hole edge => inside the polygon
+        collidingPoints.push_back( VECTOR2I( 40, 25 ) );
+
+        // On the outline edge => inside the polygon
+        collidingPoints.push_back( VECTOR2I( 0, 10 ) );
+
+        // Create points not colliding with the poly set.
+
+        // Completely outside of the polygon
+        nonCollidingPoints.push_back( VECTOR2I( 200, 200 ) );
+
+        // Inside the outline and inside a hole => outside the polygon
+        nonCollidingPoints.push_back( VECTOR2I( 15, 12 ) );
+    }
+
+    ~CollisionFixture()
+    {
+    }
+};
 
 /**
  * Declares the CollisionFixture as the boost test suite fixture.
@@ -40,7 +85,7 @@ BOOST_FIXTURE_TEST_SUITE( Collision, CollisionFixture )
 BOOST_AUTO_TEST_CASE( HasHoles )
 {
     BOOST_CHECK( !common.solidPolySet.HasHoles() );
-    BOOST_CHECK(  common.holeyPolySet.HasHoles() );
+    BOOST_CHECK( common.holeyPolySet.HasHoles() );
 }
 
 /**
@@ -50,22 +95,22 @@ BOOST_AUTO_TEST_CASE( HasHoles )
 BOOST_AUTO_TEST_CASE( PointOnEdge )
 {
     // Check points on corners
-    BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 0,50 ) ) );
+    BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 0, 50 ) ) );
 
     // Check points on outline edges
-    BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 0,10 ) ) );
+    BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 0, 10 ) ) );
 
     // Check points on hole edges
-    BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 10,11 ) ) );
+    BOOST_CHECK( common.holeyPolySet.PointOnEdge( VECTOR2I( 10, 11 ) ) );
 
     // Check points inside a hole -> not in edge
-    BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 12,12 ) ) );
+    BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 12, 12 ) ) );
 
     // Check points inside the polygon and outside any hole -> not on edge
-    BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 90,90 ) ) );
+    BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 90, 90 ) ) );
 
     // Check points outside the polygon -> not on edge
-    BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 200,200 ) ) );
+    BOOST_CHECK( !common.holeyPolySet.PointOnEdge( VECTOR2I( 200, 200 ) ) );
 }
 
 /**
@@ -109,10 +154,10 @@ BOOST_AUTO_TEST_CASE( Collide )
     // Checks with clearance > 0
 
     // Point at the offset zone outside of the outline => collision!
-    BOOST_CHECK( common.holeyPolySet.Collide( VECTOR2I( -1,10 ), 5 ) );
+    BOOST_CHECK( common.holeyPolySet.Collide( VECTOR2I( -1, 10 ), 5 ) );
 
     // Point at the offset zone outside of a hole => collision!
-    BOOST_CHECK( common.holeyPolySet.Collide( VECTOR2I( 11,11 ), 5 ) );
+    BOOST_CHECK( common.holeyPolySet.Collide( VECTOR2I( 11, 11 ), 5 ) );
 }
 
 /**
@@ -143,7 +188,7 @@ BOOST_AUTO_TEST_CASE( CollideVertexWithClearance )
     // Check that the set collides with the colliding points
     for( const VECTOR2I& point : common.holeyPoints )
     {
-        BOOST_CHECK( common.holeyPolySet.CollideVertex( point + VECTOR2I(1,1), cornerHit, 2 ) );
+        BOOST_CHECK( common.holeyPolySet.CollideVertex( point + VECTOR2I( 1, 1 ), cornerHit, 2 ) );
     }
 }
 
diff --git a/qa/shape_poly_set_refactor/test_iterator.cpp b/qa/common/geometry/test_shape_poly_set_iterator.cpp
similarity index 60%
rename from qa/shape_poly_set_refactor/test_iterator.cpp
rename to qa/common/geometry/test_shape_poly_set_iterator.cpp
index b4876a55f..8b8703702 100644
--- a/qa/shape_poly_set_refactor/test_iterator.cpp
+++ b/qa/common/geometry/test_shape_poly_set_iterator.cpp
@@ -22,12 +22,70 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
-#include <boost/test/unit_test.hpp>
-#include <boost/test/test_case_template.hpp>
-#include <geometry/shape_poly_set.h>
+#include <unit_test_utils/unit_test_utils.h>
+
 #include <geometry/shape_line_chain.h>
+#include <geometry/shape_poly_set.h>
 
-#include <qa/data/fixtures_geometry.h>
+#include "fixtures_geometry.h"
+
+/**
+* Fixture for the Iterator test suite. It contains an instance of the common data, three polysets with null segments and a vector containing their points.
+*/
+struct IteratorFixture
+{
+    // Structure to store the common data.
+    struct KI_TEST::CommonTestData common;
+
+    // Polygons to test whether the RemoveNullSegments method works
+    SHAPE_POLY_SET lastNullSegmentPolySet;
+    SHAPE_POLY_SET firstNullSegmentPolySet;
+    SHAPE_POLY_SET insideNullSegmentPolySet;
+
+    // Null segments points
+    std::vector<VECTOR2I> nullPoints;
+
+    IteratorFixture()
+    {
+        nullPoints.push_back( VECTOR2I( 100, 100 ) );
+        nullPoints.push_back( VECTOR2I( 0, 100 ) );
+        nullPoints.push_back( VECTOR2I( 0, 0 ) );
+
+        // Create a polygon with its last segment null
+        SHAPE_LINE_CHAIN polyLine;
+        polyLine.Append( nullPoints[0] );
+        polyLine.Append( nullPoints[1] );
+        polyLine.Append( nullPoints[2] );
+        polyLine.Append( nullPoints[2], true );
+        polyLine.SetClosed( true );
+
+        lastNullSegmentPolySet.AddOutline( polyLine );
+
+        // Create a polygon with its first segment null
+        polyLine.Clear();
+        polyLine.Append( nullPoints[0] );
+        polyLine.Append( nullPoints[0], true );
+        polyLine.Append( nullPoints[1] );
+        polyLine.Append( nullPoints[2] );
+        polyLine.SetClosed( true );
+
+        firstNullSegmentPolySet.AddOutline( polyLine );
+
+        // Create a polygon with an inside segment null
+        polyLine.Clear();
+        polyLine.Append( nullPoints[0] );
+        polyLine.Append( nullPoints[1] );
+        polyLine.Append( nullPoints[1], true );
+        polyLine.Append( nullPoints[2] );
+        polyLine.SetClosed( true );
+
+        insideNullSegmentPolySet.AddOutline( polyLine );
+    }
+
+    ~IteratorFixture()
+    {
+    }
+};
 
 /**
  * Declares the IteratorFixture as the boost test suite fixture.
@@ -40,7 +98,7 @@ BOOST_FIXTURE_TEST_SUITE( PolygonIterator, IteratorFixture )
 BOOST_AUTO_TEST_CASE( VertexIterator )
 {
     SHAPE_POLY_SET::ITERATOR iterator;
-    int vertexIndex = 0;
+    int                      vertexIndex = 0;
 
     for( iterator = common.holeyPolySet.IterateWithHoles(); iterator; iterator++ )
     {
@@ -55,9 +113,10 @@ BOOST_AUTO_TEST_CASE( VertexIterator )
 BOOST_AUTO_TEST_CASE( SegmentIterator )
 {
     SHAPE_POLY_SET::SEGMENT_ITERATOR iterator;
-    int segmentIndex = 0;
+    int                              segmentIndex = 0;
 
-    for( iterator = common.holeyPolySet.IterateSegmentsWithHoles(); iterator; iterator++ ){
+    for( iterator = common.holeyPolySet.IterateSegmentsWithHoles(); iterator; iterator++ )
+    {
         SEG segment = *iterator;
 
         BOOST_CHECK_EQUAL( common.holeySegments[segmentIndex].A, segment.A );
@@ -113,19 +172,18 @@ BOOST_AUTO_TEST_CASE( TotalVertices )
  */
 BOOST_AUTO_TEST_CASE( RemoveNullSegments )
 {
-    SHAPE_POLY_SET polygonSets[3] = {lastNullSegmentPolySet,
-                                     firstNullSegmentPolySet,
-                                     insideNullSegmentPolySet};
+    SHAPE_POLY_SET polygonSets[3] = { lastNullSegmentPolySet, firstNullSegmentPolySet,
+        insideNullSegmentPolySet };
 
     for( SHAPE_POLY_SET polygonSet : polygonSets )
     {
         BOOST_CHECK_EQUAL( polygonSet.TotalVertices(), 4 );
-        BOOST_CHECK_EQUAL( polygonSet.RemoveNullSegments(), 1);
+        BOOST_CHECK_EQUAL( polygonSet.RemoveNullSegments(), 1 );
         BOOST_CHECK_EQUAL( polygonSet.TotalVertices(), 3 );
 
-        BOOST_CHECK_EQUAL( polygonSet.CVertex(0), nullPoints[0] );
-        BOOST_CHECK_EQUAL( polygonSet.CVertex(1), nullPoints[1] );
-        BOOST_CHECK_EQUAL( polygonSet.CVertex(2), nullPoints[2] );
+        BOOST_CHECK_EQUAL( polygonSet.CVertex( 0 ), nullPoints[0] );
+        BOOST_CHECK_EQUAL( polygonSet.CVertex( 1 ), nullPoints[1] );
+        BOOST_CHECK_EQUAL( polygonSet.CVertex( 2 ), nullPoints[2] );
     }
 }
 
diff --git a/qa/shape_poly_set_refactor/CMakeLists.txt b/qa/shape_poly_set_refactor/CMakeLists.txt
deleted file mode 100644
index 6c023eb94..000000000
--- a/qa/shape_poly_set_refactor/CMakeLists.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# This program source code file is part of KiCad, a free EDA CAD application.
-#
-# Copyright (C) 2017 CERN
-# @author Alejandro García Montoro <alejandro.garciamontoro@xxxxxxxxx>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, you may find one here:
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# or you may search the http://www.gnu.org website for the version 2 license,
-# or you may write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-
-find_package(Boost COMPONENTS unit_test_framework REQUIRED)
-find_package( wxWidgets 3.0.0 COMPONENTS gl aui adv html core net base xml stc REQUIRED )
-
-add_definitions(-DBOOST_TEST_DYN_LINK)
-
-add_executable( qa_shape_poly_set_refactor
-    test_module.cpp
-    test_collision.cpp
-    test_iterator.cpp
-    test_segment.cpp
-)
-
-include_directories(
-    ${CMAKE_SOURCE_DIR}
-    ${CMAKE_SOURCE_DIR}/include
-    ${CMAKE_SOURCE_DIR}/polygon
-    ${CMAKE_SOURCE_DIR}/common/geometry
-    ${Boost_INCLUDE_DIR}
-)
-
-target_link_libraries( qa_shape_poly_set_refactor
-    polygon
-    common
-    polygon
-    bitmaps
-    ${Boost_FILESYSTEM_LIBRARY}
-    ${Boost_SYSTEM_LIBRARY}
-    ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
-    ${wxWidgets_LIBRARIES}
-)
-
-add_dependencies( qa_shape_poly_set_refactor pcbnew )
-
-add_test( NAME shape_poly_set_refactor
-    COMMAND qa_shape_poly_set_refactor
-)
diff --git a/qa/shape_poly_set_refactor/test_module.cpp b/qa/shape_poly_set_refactor/test_module.cpp
deleted file mode 100644
index 4f99b55ab..000000000
--- a/qa/shape_poly_set_refactor/test_module.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2017 CERN
- * @author Alejandro García Montoro <alejandro.garciamontoro@xxxxxxxxx>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you may find one here:
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- * or you may search the http://www.gnu.org website for the version 2 license,
- * or you may write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-/**
- * Main file for the geometry tests to be compiled
- */
-
-#define BOOST_TEST_MAIN
-#define BOOST_TEST_MODULE "CPolyLine -> SHAPE_POLY_SET refactor module"
-
-#include <boost/test/unit_test.hpp>
-- 
2.20.1

From 4a694d164d8351d17e0e5df2783b8220426ba512 Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Thu, 24 Jan 2019 14:14:08 +0000
Subject: [PATCH 4/6] QA: Reinstate polygon_triangulation utility

This utility has been disabled since the eeschema GAL merge. It
can be reinstated as part of the qa_pcbnew_tools framework.
---
 Documentation/development/testing.md          |  1 +
 qa/CMakeLists.txt                             |  1 -
 qa/pcbnew_tools/CMakeLists.txt                |  2 +
 qa/pcbnew_tools/pcbnew_tools.cpp              |  2 +
 .../polygon_triangulation.cpp}                | 27 +++++-
 .../polygon_triangulation.h                   | 32 +++++++
 qa/polygon_triangulation/CMakeLists.txt       | 92 -------------------
 7 files changed, 59 insertions(+), 98 deletions(-)
 rename qa/{polygon_triangulation/test_polygon_triangulation.cpp => pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp} (92%)
 create mode 100644 qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.h
 delete mode 100644 qa/polygon_triangulation/CMakeLists.txt

diff --git a/Documentation/development/testing.md b/Documentation/development/testing.md
index 5130dad0a..3bad8e3a5 100644
--- a/Documentation/development/testing.md
+++ b/Documentation/development/testing.md
@@ -172,6 +172,7 @@ parameters, refer to the tools' usage test (`-h`).
     * `drc`: Run and benchmark certain DRC functions on a user-provided `.kicad_pcb` files
     * `pcb_parser`: Parse user-provided `.kicad_pcb` files
     * `polygon_generator`: Dump polygons found on a PCB to the console
+    * `polygon_triangulation`: Perform triangulation of zone polygons on PCBs
 
 # Fuzz testing {#fuzz-testing}
 
diff --git a/qa/CMakeLists.txt b/qa/CMakeLists.txt
index 6502a461c..ea0e6712d 100644
--- a/qa/CMakeLists.txt
+++ b/qa/CMakeLists.txt
@@ -27,4 +27,3 @@ add_subdirectory( common_tools )
 add_subdirectory( pcbnew_tools )
 
 # add_subdirectory( pcb_test_window )
-# add_subdirectory( polygon_triangulation )
diff --git a/qa/pcbnew_tools/CMakeLists.txt b/qa/pcbnew_tools/CMakeLists.txt
index 9b01c24e1..372946ee4 100644
--- a/qa/pcbnew_tools/CMakeLists.txt
+++ b/qa/pcbnew_tools/CMakeLists.txt
@@ -35,6 +35,8 @@ add_executable( qa_pcbnew_tools
 
     tools/polygon_generator/polygon_generator.cpp
 
+    tools/polygon_triangulation/polygon_triangulation.cpp
+
     # Older CMakes cannot link OBJECT libraries
     # https://cmake.org/pipermail/cmake/2013-November/056263.html
     $<TARGET_OBJECTS:pcbnew_kiface_objects>
diff --git a/qa/pcbnew_tools/pcbnew_tools.cpp b/qa/pcbnew_tools/pcbnew_tools.cpp
index 0753e4f8f..4b810b8b9 100644
--- a/qa/pcbnew_tools/pcbnew_tools.cpp
+++ b/qa/pcbnew_tools/pcbnew_tools.cpp
@@ -26,6 +26,7 @@
 #include "tools/drc_tool/drc_tool.h"
 #include "tools/pcb_parser/pcb_parser_tool.h"
 #include "tools/polygon_generator/polygon_generator.h"
+#include "tools/polygon_triangulation/polygon_triangulation.h"
 
 /**
  * List of registered tools.
@@ -37,6 +38,7 @@ const static std::vector<KI_TEST::UTILITY_PROGRAM*> known_tools = {
     &drc_tool,
     &pcb_parser_tool,
     &polygon_generator_tool,
+    &polygon_triangulation_tool,
 };
 
 
diff --git a/qa/polygon_triangulation/test_polygon_triangulation.cpp b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
similarity index 92%
rename from qa/polygon_triangulation/test_polygon_triangulation.cpp
rename to qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
index 0410e1225..d10af9a6b 100644
--- a/qa/polygon_triangulation/test_polygon_triangulation.cpp
+++ b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.cpp
@@ -22,6 +22,8 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
+#include "polygon_triangulation.h"
+
 #include <geometry/shape_poly_set.h>
 #include <geometry/shape_line_chain.h>
 
@@ -198,7 +200,7 @@ aResult->clear();
         std::swap( (*aResult) [0], (*aResult)[outline] );
 }
 
-BOARD* loadBoard( const std::string& filename )
+BOARD* loadBoardTri( const std::string& filename )
 {
     PLUGIN::RELEASER pi( new PCB_IO );
     BOARD* brd = nullptr;
@@ -219,12 +221,18 @@ BOARD* loadBoard( const std::string& filename )
     return brd;
 }
 
-int main( int argc, char *argv[] )
+enum POLY_TRI_RET_CODES
+{
+    LOAD_FAILED = KI_TEST::RET_CODES::TOOL_SPECIFIC,
+};
+
+
+int polygon_triangulation_main( int argc, char *argv[] )
 {
-    auto brd = loadBoard( argc > 1 ? argv[1] : "../../../../tests/dp.kicad_pcb" );
+    auto brd = loadBoardTri( argc > 1 ? argv[1] : "../../../../tests/dp.kicad_pcb" );
 
     if( !brd )
-        return -1;
+        return POLY_TRI_RET_CODES::LOAD_FAILED;
 
 
     PROF_COUNTER cnt( "allBoard" );
@@ -278,6 +286,15 @@ int main( int argc, char *argv[] )
 
     delete brd;
 
-    return 0;
+    return KI_TEST::RET_CODES::OK;
 
 }
+
+/*
+ * Define the tool interface
+ */
+KI_TEST::UTILITY_PROGRAM polygon_triangulation_tool = {
+    "polygon_triangulation",
+    "Process polygon trianguation on a PCB",
+    polygon_triangulation_main,
+};
\ No newline at end of file
diff --git a/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.h b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.h
new file mode 100644
index 000000000..b3410db60
--- /dev/null
+++ b/qa/pcbnew_tools/tools/polygon_triangulation/polygon_triangulation.h
@@ -0,0 +1,32 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef PCBNEW_TOOLS_POLYGON_TRIANGULATION_UTILITY_H
+#define PCBNEW_TOOLS_POLYGON_TRIANGULATION_UTILITY_H
+
+#include <utility_program.h>
+
+/// A tool to parse kicad PCBs from the command line
+extern KI_TEST::UTILITY_PROGRAM polygon_triangulation_tool;
+
+#endif //PCBNEW_TOOLS_POLYGON_TRIANGULATION_UTILITY_H
\ No newline at end of file
diff --git a/qa/polygon_triangulation/CMakeLists.txt b/qa/polygon_triangulation/CMakeLists.txt
deleted file mode 100644
index 228120691..000000000
--- a/qa/polygon_triangulation/CMakeLists.txt
+++ /dev/null
@@ -1,92 +0,0 @@
-#
-# This program source code file is part of KiCad, a free EDA CAD application.
-#
-# Copyright (C) 2017 CERN
-# @author Alejandro García Montoro <alejandro.garciamontoro@xxxxxxxxx>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, you may find one here:
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# or you may search the http://www.gnu.org website for the version 2 license,
-# or you may write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-
-#find_package(Boost COMPONENTS unit_test_framework REQUIRED)
-#find_package( wxWidgets 3.0.0 COMPONENTS gl aui adv html core net base xml stc REQUIRED )
-
-add_definitions(-DPCBNEW -DBOOST_TEST_DYN_LINK)
-
-if( BUILD_GITHUB_PLUGIN )
-    set( GITHUB_PLUGIN_LIBRARIES github_plugin )
-endif()
-
-add_dependencies( pnsrouter pcbcommon pcad2kicadpcb ${GITHUB_PLUGIN_LIBRARIES} )
-
-add_executable(test_polygon_triangulation
-  ../qa_utils/mocks.cpp
-  ../../common/base_units.cpp
-  test_polygon_triangulation.cpp
-)
-
-include_directories( BEFORE ${INC_BEFORE} )
-include_directories(
-    ${CMAKE_SOURCE_DIR}
-    ${CMAKE_SOURCE_DIR}/include
-    ${CMAKE_SOURCE_DIR}/3d-viewer
-    ${CMAKE_SOURCE_DIR}/common
-    ${CMAKE_SOURCE_DIR}/pcbnew
-    ${CMAKE_SOURCE_DIR}/pcbnew/router
-    ${CMAKE_SOURCE_DIR}/pcbnew/tools
-    ${CMAKE_SOURCE_DIR}/pcbnew/dialogs
-    ${CMAKE_SOURCE_DIR}/polygon
-    ${CMAKE_SOURCE_DIR}/common/geometry
-    ${CMAKE_SOURCE_DIR}/qa/common
-    ${Boost_INCLUDE_DIR}
-    ${INC_AFTER}
-)
-
-target_link_libraries( test_polygon_triangulation
-    polygon
-    pnsrouter
-    common
-    pcbcommon
-    bitmaps
-    polygon
-    pnsrouter
-    common
-    pcbcommon
-    bitmaps
-    polygon
-    pnsrouter
-    common
-    pcbcommon
-    bitmaps
-    polygon
-    pnsrouter
-    common
-    pcbcommon
-    bitmaps
-    gal
-    pcad2kicadpcb
-    common
-    pcbcommon
-    ${GITHUB_PLUGIN_LIBRARIES}
-    common
-    pcbcommon
-    ${Boost_FILESYSTEM_LIBRARY}
-    ${Boost_SYSTEM_LIBRARY}
-    ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
-    ${wxWidgets_LIBRARIES}
-)
-
-
-- 
2.20.1


Follow ups