KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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#define BOOST_NO_AUTO_PTR
28
29#include <boost/test/unit_test.hpp>
30#include <turtle/mock.hpp>
31
33
34#include <functional>
35#include <optional>
36#include <set>
37
38#include <wx/gdicmn.h>
39
49#if BOOST_VERSION >= 105900
50#define HAVE_EXPECTED_FAILURES
51#endif
52
62#undef BOOST_TEST
63
64
65#if BOOST_VERSION < 105900
66
67/*
68 * BOOST_TEST_INFO is not available before 1.59. It's not critical for
69 * test pass/fail, it's just info, so just pass along to a logging
70 * function.
71 *
72 * This can be removed when our minimum boost version is 1.59 or higher.
73 */
74#define BOOST_TEST_INFO( A ) BOOST_TEST_MESSAGE( A )
75
76/*
77 *
78 * BOOST_TEST_CONTEXT provides scoped info, but again, only after 1.59.
79 * Replacing with a call to BOOST_TEST_MESSAGE will work, and the
80 * scoping will still work for newer boosts.
81 *
82 * This can be removed when our minimum boost version is 1.59 or higher.
83 */
84#define BOOST_TEST_CONTEXT( A ) BOOST_TEST_MESSAGE( A );
85
86#endif
87
88/*
89 * Boost hides the configuration point for print_log_value in different
90 * namespaces between < 1.59 and >= 1.59.
91 *
92 * The macros can be used to open and close the right level of namespacing
93 * based on the version.
94 *
95 * We could just use a conditionally defined namespace alias, but that
96 * doesn't work in GCC <7 (GCC bug #56480)
97 *
98 * From Boost 1.64, this should be done with boost_test_print_type,
99 * and these defines can be removed once all logging functions use that.
100 */
101#if BOOST_VERSION >= 105900
102#define BOOST_TEST_PRINT_NAMESPACE_OPEN \
103 boost \
104 { \
105 namespace test_tools \
106 { \
107 namespace tt_detail
108#define BOOST_TEST_PRINT_NAMESPACE_CLOSE }}
109#else
110#define BOOST_TEST_PRINT_NAMESPACE_OPEN \
111 boost \
112 { \
113 namespace test_tools
114#define BOOST_TEST_PRINT_NAMESPACE_CLOSE }
115#endif
116
123#if BOOST_VERSION < 106400
124
126{
127template <>
128struct print_log_value<std::nullptr_t>
129{
130 inline void operator()( std::ostream& os, std::nullptr_t const& p )
131 {
132 os << "nullptr";
133 }
134};
135}
137
138#endif
139
140
141template<class T>
143{
144 PRINTABLE_OPT( const std::optional<T>& aOpt ) : m_Opt( aOpt ){};
145 PRINTABLE_OPT( const T& aVal ) : m_Opt( aVal ){};
146
147 std::optional<T> m_Opt;
148};
149
150
154#define KI_CHECK_OPT_EQUAL( lhs, rhs ) \
155 BOOST_CHECK_EQUAL( PRINTABLE_OPT( lhs ), PRINTABLE_OPT( rhs ) )
156
157
158template <class T>
159inline std::ostream& operator<<( std::ostream& aOs, const PRINTABLE_OPT<T>& aOptional )
160{
161 if( aOptional.m_Opt.has_value() )
162 aOs << *aOptional.m_Opt;
163 else
164 aOs << "nullopt";
165
166 return aOs;
167}
168
169
170template <class L, class R>
171inline bool operator==( const PRINTABLE_OPT<L>& aLhs, const PRINTABLE_OPT<R>& aRhs )
172{
173 if( !aLhs.m_Opt.has_value() && !aRhs.m_Opt.has_value() )
174 return true; // both nullopt
175
176 return aLhs.m_Opt.has_value() && aRhs.m_Opt.has_value() && *aLhs.m_Opt == *aRhs.m_Opt;
177}
178
179
180template <class L, class R>
181inline bool operator!=( const PRINTABLE_OPT<L>& aLhs, const PRINTABLE_OPT<R>& aRhs )
182{
183 return !( aLhs == aRhs );
184}
185
186
188{
189
193template <typename T>
194struct print_log_value<std::vector<T>>
195{
196 inline void operator()( std::ostream& os, std::vector<T> const& aVec )
197 {
198 os << "std::vector size " << aVec.size() << " [";
199
200 for( const auto& i : aVec )
201 {
202 os << "\n ";
203 print_log_value<T>()( os, i );
204 }
205
206 os << "]";
207 }
208};
209
213template <typename K, typename V>
214struct print_log_value<std::map<K, V>>
215{
216 inline void operator()( std::ostream& os, std::map<K, V> const& aMap )
217 {
218 os << "std::map size " << aMap.size() << " [";
219
220 for( const auto& [key, value] : aMap )
221 {
222 os << "\n ";
223 print_log_value<K>()( os, key );
224 os << " = ";
225 print_log_value<K>()( os, value );
226 }
227
228 os << "]";
229 }
230};
231
235template <typename K, typename V>
236struct print_log_value<std::pair<K, V>>
237{
238 inline void operator()( std::ostream& os, std::pair<K, V> const& aPair )
239 {
240 os << "[";
241 print_log_value<K>()( os, aPair.first );
242 os << ", ";
243 print_log_value<K>()( os, aPair.second );
244 os << "]";
245 }
246};
247
252template <>
253struct print_log_value<wxPoint>
254{
255 void operator()( std::ostream& os, wxPoint const& aVec );
256};
257
258}
260
261
262namespace KI_TEST
263{
264
265template <typename EXP_CONT> using EXP_OBJ = typename EXP_CONT::value_type;
266template <typename FOUND_CONT> using FOUND_OBJ = typename FOUND_CONT::value_type;
267
284template <typename EXP_OBJ, typename FOUND_OBJ>
285using MATCH_PRED = std::function<bool( const EXP_OBJ&, const FOUND_OBJ& )>;
286
321template <typename EXP_CONT, typename FOUND_CONT, typename MATCH_PRED>
322void CheckUnorderedMatches( const EXP_CONT& aExpected, const FOUND_CONT& aFound,
323 MATCH_PRED aMatchPredicate )
324{
325 using EXP_OBJ = typename EXP_CONT::value_type;
326
327 // set of object we've already found
328 std::set<const EXP_OBJ*> matched;
329
330 // fill the set of object that match
331 for( const auto& found : aFound )
332 {
333 for( const auto& expected : aExpected )
334 {
335 if( aMatchPredicate( expected, found ) )
336 {
337 matched.insert( &expected );
338 break;
339 }
340 }
341 }
342
343 // first check every expected object was "found"
344 for( const EXP_OBJ& exp : aExpected )
345 {
346 BOOST_CHECK_MESSAGE( matched.count( &exp ) > 0, "Expected item was not found. Expected: \n"
347 << exp );
348 }
349
350 // check every "found" object was expected
351 for( const EXP_OBJ* found : matched )
352 {
353 const bool was_expected = std::find_if( aExpected.begin(), aExpected.end(),
354 [found]( const EXP_OBJ& aObj )
355 {
356 return &aObj == found;
357 } ) != aExpected.end();
358
359 BOOST_CHECK_MESSAGE( was_expected, "Found item was not expected. Found: \n" << *found );
360 }
361}
362
363
367template <typename T>
368bool CollectionHasNoDuplicates( const T& aCollection )
369{
370 T sorted = aCollection;
371 std::sort( sorted.begin(), sorted.end() );
372
373 return std::adjacent_find( sorted.begin(), sorted.end() ) == sorted.end();
374}
375
376
383#ifdef DEBUG
384#define CHECK_WX_ASSERT( STATEMENT ) BOOST_CHECK_THROW( STATEMENT, KI_TEST::WX_ASSERT_ERROR );
385#else
386#define CHECK_WX_ASSERT( STATEMENT )
387#endif
388
397std::string GetEeschemaTestDataDir();
398
399} // namespace KI_TEST
400
401#endif // UNIT_TEST_UTILS__H
Before Boost 1.64, nullptr_t wasn't handled.
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.
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
bool CollectionHasNoDuplicates(const T &aCollection)
Predicate to check a collection has no duplicate elements.
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,...
typename FOUND_CONT::value_type FOUND_OBJ
typename EXP_CONT::value_type EXP_OBJ
STL namespace.
void operator()(std::ostream &os, std::map< K, V > const &aMap)
void operator()(std::ostream &os, std::nullptr_t const &p)
void operator()(std::ostream &os, std::pair< K, V > const &aPair)
void operator()(std::ostream &os, std::vector< T > const &aVec)
std::optional< T > m_Opt
PRINTABLE_OPT(const T &aVal)
PRINTABLE_OPT(const std::optional< T > &aOpt)
VECTOR3I expected(15, 30, 45)
#define BOOST_TEST_PRINT_NAMESPACE_CLOSE
bool operator!=(const PRINTABLE_OPT< L > &aLhs, const PRINTABLE_OPT< R > &aRhs)
bool operator==(const PRINTABLE_OPT< L > &aLhs, const PRINTABLE_OPT< R > &aRhs)
std::ostream & operator<<(std::ostream &aOs, const PRINTABLE_OPT< T > &aOptional)