KiCad PCB EDA Suite
unit_test_utils.h
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #ifndef UNIT_TEST_UTILS__H
25 #define UNIT_TEST_UTILS__H
26 
27 #include <boost/test/unit_test.hpp>
28 
30 
31 #include <functional>
32 #include <set>
33 
34 #include <wx/gdicmn.h>
44 #if BOOST_VERSION >= 105900
45 #define HAVE_EXPECTED_FAILURES
46 #endif
47 
57 #undef BOOST_TEST
58 
59 
60 #if BOOST_VERSION < 105900
61 
62 /*
63  * BOOST_TEST_INFO is not available before 1.59. It's not critical for
64  * test pass/fail, it's just info, so just pass along to a logging
65  * function.
66  *
67  * This can be removed when our minimum boost version is 1.59 or higher.
68  */
69 #define BOOST_TEST_INFO( A ) BOOST_TEST_MESSAGE( A )
70 
71 /*
72  *
73  * BOOST_TEST_CONTEXT provides scoped info, but again, only after 1.59.
74  * Replacing with a call to BOOST_TEST_MESSAGE will work, and the
75  * scoping will still work for newer boosts.
76  *
77  * This can be removed when our minimum boost version is 1.59 or higher.
78  */
79 #define BOOST_TEST_CONTEXT( A ) BOOST_TEST_MESSAGE( A );
80 
81 #endif
82 
83 /*
84  * Boost hides the configuration point for print_log_value in different
85  * namespaces between < 1.59 and >= 1.59.
86  *
87  * The macros can be used to open and close the right level of namespacing
88  * based on the version.
89  *
90  * We could just use a conditionally defined namespace alias, but that
91  * doesn't work in GCC <7 (GCC bug #56480)
92  *
93  * From Boost 1.64, this should be done with boost_test_print_type,
94  * and these defines can be removed once all logging functions use that.
95  */
96 #if BOOST_VERSION >= 105900
97 #define BOOST_TEST_PRINT_NAMESPACE_OPEN \
98  boost \
99  { \
100  namespace test_tools \
101  { \
102  namespace tt_detail
103 #define BOOST_TEST_PRINT_NAMESPACE_CLOSE }}
104 #else
105 #define BOOST_TEST_PRINT_NAMESPACE_OPEN \
106  boost \
107  { \
108  namespace test_tools
109 #define BOOST_TEST_PRINT_NAMESPACE_CLOSE }
110 #endif
111 
118 #if BOOST_VERSION < 106400
119 
121 {
122 template <>
123 struct print_log_value<std::nullptr_t>
124 {
125  inline void operator()( std::ostream& os, std::nullptr_t const& p )
126  {
127  os << "nullptr";
128  }
129 };
130 }
132 
133 #endif
134 
135 
137 {
138 
142 template <typename T>
143 struct print_log_value<std::vector<T>>
144 {
145  inline void operator()( std::ostream& os, std::vector<T> const& aVec )
146  {
147  os << "std::vector size " << aVec.size() << "[";
148 
149  for( const auto& i : aVec )
150  {
151  os << "\n ";
152  print_log_value<T>()( os, i );
153  }
154 
155  os << "]";
156  }
157 };
158 
163 template <>
164 struct print_log_value<wxPoint>
165 {
166  void operator()( std::ostream& os, wxPoint const& aVec );
167 };
168 }
170 
171 
172 namespace KI_TEST
173 {
174 
175 template <typename EXP_CONT> using EXP_OBJ = typename EXP_CONT::value_type;
176 template <typename FOUND_CONT> using FOUND_OBJ = typename FOUND_CONT::value_type;
177 
194 template <typename EXP_OBJ, typename FOUND_OBJ>
195 using MATCH_PRED = std::function<bool( const EXP_OBJ&, const FOUND_OBJ& )>;
196 
231 template <typename EXP_CONT, typename FOUND_CONT, typename MATCH_PRED>
233  const EXP_CONT& aExpected, const FOUND_CONT& aFound, MATCH_PRED aMatchPredicate )
234 {
235  using EXP_OBJ = typename EXP_CONT::value_type;
236 
237  // set of object we've already found
238  std::set<const EXP_OBJ*> matched;
239 
240  // fill the set of object that match
241  for( const auto& found : aFound )
242  {
243  for( const auto& expected : aExpected )
244  {
245  if( aMatchPredicate( expected, found ) )
246  {
247  matched.insert( &expected );
248  break;
249  }
250  }
251  }
252 
253  // first check every expected object was "found"
254  for( const EXP_OBJ& exp : aExpected )
255  {
256  BOOST_CHECK_MESSAGE( matched.count( &exp ) > 0, "Expected item was not found. Expected: \n"
257  << exp );
258  }
259 
260  // check every "found" object was expected
261  for( const EXP_OBJ* found : matched )
262  {
263  const bool was_expected =
264  std::find_if( aExpected.begin(), aExpected.end(),
265  [found]( const EXP_OBJ& aObj ) { return &aObj == found; } )
266  != aExpected.end();
267 
268  BOOST_CHECK_MESSAGE( was_expected, "Found item was not expected. Found: \n" << *found );
269  }
270 }
271 
272 
276 template <typename T>
277 bool CollectionHasNoDuplicates( const T& aCollection )
278 {
279  T sorted = aCollection;
280  std::sort( sorted.begin(), sorted.end() );
281 
282  return std::adjacent_find( sorted.begin(), sorted.end() ) == sorted.end();
283 }
284 
285 
292 #ifdef DEBUG
293 #define CHECK_WX_ASSERT( STATEMENT ) BOOST_CHECK_THROW( STATEMENT, KI_TEST::WX_ASSERT_ERROR );
294 #else
295 #define CHECK_WX_ASSERT( STATEMENT )
296 #endif
297 
298 } // namespace KI_TEST
299 
300 #endif // UNIT_TEST_UTILS__H
Before Boost 1.64, nullptr_t wasn't handled.
void operator()(std::ostream &os, std::nullptr_t const &p)
typename FOUND_CONT::value_type FOUND_OBJ
std::function< bool(const EXP_OBJ &, const FOUND_OBJ &)> MATCH_PRED
A match predicate: check that a "found" object is equivalent to or represents an "expected" object,...
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:56
T
enum T contains all this lexer's tokens.
#define BOOST_TEST_PRINT_NAMESPACE_CLOSE
void CheckUnorderedMatches(const EXP_CONT &aExpected, const FOUND_CONT &aFound, MATCH_PRED aMatchPredicate)
Check that a container of "found" objects matches a container of "expected" objects.
bool CollectionHasNoDuplicates(const T &aCollection)
Predicate to check a collection has no duplicate elements.
void operator()(std::ostream &os, std::vector< T > const &aVec)
typename EXP_CONT::value_type EXP_OBJ