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 The 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef UNIT_TEST_UTILS__H
21#define UNIT_TEST_UTILS__H
22
23#define BOOST_NO_AUTO_PTR
24
25#include <boost/test/unit_test.hpp>
26#include <turtle/mock.hpp>
27
29
30#include <cstdint>
31#include <functional>
32#include <optional>
33#include <set>
34#include <vector>
35
36#include <wx/gdicmn.h>
37#include <wx/string.h>
38
39
40template<class T>
42{
43 PRINTABLE_OPT( const std::optional<T>& aOpt ) : m_Opt( aOpt ){};
44 PRINTABLE_OPT( const T& aVal ) : m_Opt( aVal ){};
45
46 std::optional<T> m_Opt;
47};
48
49
53#define KI_CHECK_OPT_EQUAL( lhs, rhs ) \
54 BOOST_CHECK_EQUAL( PRINTABLE_OPT( lhs ), PRINTABLE_OPT( rhs ) )
55
56
57template <class T>
58inline std::ostream& operator<<( std::ostream& aOs, const PRINTABLE_OPT<T>& aOptional )
59{
60 if( aOptional.m_Opt.has_value() )
61 aOs << *aOptional.m_Opt;
62 else
63 aOs << "nullopt";
64
65 return aOs;
66}
67
68
69template <class L, class R>
70inline bool operator==( const PRINTABLE_OPT<L>& aLhs, const PRINTABLE_OPT<R>& aRhs )
71{
72 if( !aLhs.m_Opt.has_value() && !aRhs.m_Opt.has_value() )
73 return true; // both nullopt
74
75 return aLhs.m_Opt.has_value() && aRhs.m_Opt.has_value() && *aLhs.m_Opt == *aRhs.m_Opt;
76}
77
78
79template <class L, class R>
80inline bool operator!=( const PRINTABLE_OPT<L>& aLhs, const PRINTABLE_OPT<R>& aRhs )
81{
82 return !( aLhs == aRhs );
83}
84
85
86// boost_test_print_type has to be in the same namespace as the printed type
87namespace std
88{
89
93template <typename T>
94std::ostream& boost_test_print_type( std::ostream& os, std::vector<T> const& aVec )
95{
96 os << "std::vector size " << aVec.size() << " [";
97
98 for( const auto& i : aVec )
99 {
100 os << "\n " << i;
101 }
102
103 os << "]";
104 return os;
105}
106
110template <typename K, typename V>
111std::ostream& boost_test_print_type( std::ostream& os, std::map<K, V> const& aMap )
112{
113 os << "std::map size " << aMap.size() << " [";
114
115 for( const auto& [key, value] : aMap )
116 {
117 os << "\n " << key << " = " << value;
118 }
119
120 os << "]";
121 return os;
122}
123
127template <typename K, typename V>
128std::ostream& boost_test_print_type( std::ostream& os, std::pair<K, V> const& aPair )
129{
130 os << "[" << aPair.first << ", " << aPair.second << "]";
131 return os;
132}
133
134} // namespace std
135
136
137//-----------------------------------------------------------------------------+
138// Boost.Test printing helpers for wx types / wide string literals
139//-----------------------------------------------------------------------------+
140
141// C++20 removed operator<<(ostream&, const wchar_t*) (P1423R3), which breaks wxString streaming
142// via implicit wchar_t* conversion in Boost.Test's lazy_ostream (used by BOOST_TEST_CONTEXT,
143// BOOST_TEST_MESSAGE, BOOST_CHECK_MESSAGE, and BOOST_FAIL).
144inline std::ostream& boost_test_print_type( std::ostream& os, const wxString& v )
145{
146#if wxUSE_UNICODE
147 os << v.ToUTF8().data();
148#else
149 os << v.c_str();
150#endif
151 return os;
152}
153
154
155// Wide string literal arrays
156template <std::size_t N>
157std::ostream& boost_test_print_type( std::ostream& os, const wchar_t ( &ws )[N] )
158{
159 wxString tmp( ws );
160#if wxUSE_UNICODE
161 os << tmp.ToUTF8().data();
162#else
163 os << tmp;
164#endif
165 return os;
166}
167
168
169namespace boost { namespace test_tools { namespace tt_detail {
170
171template<std::size_t N>
172struct print_log_value<wchar_t[ N ]>
173{
174 void operator()( std::ostream& os, const wchar_t (&ws)[ N ] )
175 {
176 wxString tmp( ws );
177#if wxUSE_UNICODE
178 os << tmp.ToUTF8().data();
179#else
180 os << tmp;
181#endif
182 }
183};
184
185}}} // namespace boost::test_tools::tt_detail
186
187
192std::ostream& boost_test_print_type( std::ostream& os, wxPoint const& aVec );
193
194namespace KI_TEST
195{
196
197template <typename EXP_CONT> using EXP_OBJ = typename EXP_CONT::value_type;
198template <typename FOUND_CONT> using FOUND_OBJ = typename FOUND_CONT::value_type;
199
216template <typename EXP_OBJ, typename FOUND_OBJ>
217using MATCH_PRED = std::function<bool( const EXP_OBJ&, const FOUND_OBJ& )>;
218
253template <typename EXP_CONT, typename FOUND_CONT, typename MATCH_PRED>
254void CheckUnorderedMatches( const EXP_CONT& aExpected, const FOUND_CONT& aFound,
255 MATCH_PRED aMatchPredicate )
256{
257 using EXP_OBJ = typename EXP_CONT::value_type;
258
259 // set of object we've already found
260 std::set<const EXP_OBJ*> matched;
261
262 // fill the set of object that match
263 for( const auto& found : aFound )
264 {
265 for( const auto& expected : aExpected )
266 {
267 if( aMatchPredicate( expected, found ) )
268 {
269 matched.insert( &expected );
270 break;
271 }
272 }
273 }
274
275 // first check every expected object was "found"
276 for( const EXP_OBJ& exp : aExpected )
277 {
278 BOOST_CHECK_MESSAGE( matched.count( &exp ) > 0, "Expected item was not found. Expected: \n"
279 << exp );
280 }
281
282 // check every "found" object was expected
283 for( const EXP_OBJ* found : matched )
284 {
285 const bool was_expected = std::find_if( aExpected.begin(), aExpected.end(),
286 [found]( const EXP_OBJ& aObj )
287 {
288 return &aObj == found;
289 } ) != aExpected.end();
290
291 BOOST_CHECK_MESSAGE( was_expected, "Found item was not expected. Found: \n" << *found );
292 }
293}
294
295
299template <typename T>
300bool CollectionHasNoDuplicates( const T& aCollection )
301{
302 T sorted = aCollection;
303 std::sort( sorted.begin(), sorted.end() );
304
305 return std::adjacent_find( sorted.begin(), sorted.end() ) == sorted.end();
306}
307
308
316{
317 std::string m_CaseName;
318
319 friend std::ostream& operator<<( std::ostream& os, const NAMED_CASE& aCase )
320 {
321 os << aCase.m_CaseName;
322 return os;
323 }
324};
325
326
335#if wxDEBUG_LEVEL > 0
336#define CHECK_WX_ASSERT( STATEMENT ) BOOST_CHECK_THROW( STATEMENT, KI_TEST::WX_ASSERT_ERROR );
337#else
338#define CHECK_WX_ASSERT( STATEMENT )
339#endif
340
349std::string GetEeschemaTestDataDir();
350
351std::string GetTestDataRootDir();
352
361std::vector<uint8_t> LoadBinaryData( const std::string& aFilePath, std::optional<size_t> aLoadBytes = std::nullopt );
362
363void SetMockConfigDir();
364
365} // namespace KI_TEST
366
367#endif // UNIT_TEST_UTILS__H
std::string GetTestDataRootDir()
std::vector< uint8_t > LoadBinaryData(const std::string &aFilePath, std::optional< size_t > aLoadBytes=std::nullopt)
Load the contents of a file into a vector of bytes.
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.
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,...
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
typename EXP_CONT::value_type EXP_OBJ
bool CollectionHasNoDuplicates(const T &aCollection)
Predicate to check a collection has no duplicate elements.
void SetMockConfigDir()
STL namespace.
std::ostream & boost_test_print_type(std::ostream &os, std::vector< T > const &aVec)
Boost print helper for generic vectors.
A named data-driven test case.
friend std::ostream & operator<<(std::ostream &os, const NAMED_CASE &aCase)
std::optional< T > m_Opt
PRINTABLE_OPT(const T &aVal)
PRINTABLE_OPT(const std::optional< T > &aOpt)
void operator()(std::ostream &os, const wchar_t(&ws)[N])
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_MESSAGE(totalMismatches==0, std::to_string(totalMismatches)+" board(s) with strategy disagreements")
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)
std::ostream & boost_test_print_type(std::ostream &os, const wxString &v)