The Battle for Wesnoth  1.19.0-dev
test_lexical_cast.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-test"
17 
18 #include "lexical_cast.hpp"
19 #include "log.hpp"
20 
21 #include <boost/test/unit_test.hpp>
22 
23 #include <tuple>
24 
25 namespace test_throw {
26 
27 #ifdef _MSC_VER
28 #pragma warning(push)
29 #pragma warning(disable:4702)
30 #endif
31 
32 #define LEXICAL_CAST_DEBUG
33 #include "lexical_cast.hpp"
34 
35 #ifdef _MSC_VER
36 #pragma warning(pop)
37 #endif
38 
39 using test_match_types = std::tuple<
40  /* note Wesnoth's coding style doesn't allow w_char so ignore them. */
41 
42  bool,
43 
44  /*
45  * We don't want chars to match since a string cast of a char is
46  * ambiguous; does the user want it interpreted as a char or as a number?
47  * But as long as that hasn't been fixed, leave the char.
48  */
49  char, signed char, unsigned char,
50  short, int, long, long long,
51  unsigned short, unsigned int, unsigned long, unsigned long long
52  >;
53 
54 using test_nomatch_types = std::tuple<float, double, long double>;
55 
56 using test_types = decltype(std::tuple_cat(test_nomatch_types{}, test_match_types{}));
57 
58 namespace {
59 
60  std::string result;
61 
62 bool validate(const char* str)
63 {
64  if(str != result) {
65  PLAIN_LOG << "Received " << str << '\n'
66  << "Expected " << result << '\n';
67  return false;
68  } else {
69  return true;
70  }
71 }
72 
73 template<typename Test, typename... Types>
74 constexpr bool contains_type(std::tuple<Types...>)
75 {
76  return (std::is_same_v<Test, Types> || ...);
77 }
78 
79 } // namespace
80 
81 #define TEST_CASE(type_send, initializer) \
82  { \
83  type_send val = initializer value; \
84  \
85  BOOST_CHECK_EXCEPTION( \
86  lexical_cast<std::string>(val), const char*, validate); \
87  }
88 
89 BOOST_AUTO_TEST_CASE_TEMPLATE(test_lexical_cast_throw, T, test_types)
90 {
91  T value = T();
92 
93  if constexpr(contains_type<T>(test_match_types{})) {
94  result = "specialized - To std::string - From integral (pointer)";
95  } else {
96  result = "generic";
97  }
98 
99  TEST_CASE(T, );
100  TEST_CASE(const T, );
101 
102  TEST_CASE(T&, );
103  TEST_CASE(const T&, );
104 
105  TEST_CASE(T*, &);
106  TEST_CASE(const T*, &);
107 
108  TEST_CASE(T* const, &);
109  TEST_CASE(const T* const, &);
110 }
111 
112 #undef TEST_CASE
113 
115  signed char
116  , short
117  , int
118  , long>;
119 
121  test_lexical_cast_signed, T, test_lexical_cast_signed_types)
122 {
123  result = "specialized - To signed - From (const) char*";
124 
125  const char* value = "test";
126  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
127  value), const char*, validate);
128  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
129  const_cast<char*>(value)), const char*, validate);
130 
131  result = "specialized - To signed - From std::string";
132 
133  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
134  std::string(value)), const char*, validate);
135 }
136 
137 BOOST_AUTO_TEST_CASE(test_lexical_cast_long_long)
138 {
139  result = "specialized - To long long - From (const) char*";
140 
141  const char* value = "test";
142  BOOST_CHECK_EXCEPTION(lexical_cast<long long>(
143  value), const char*, validate);
144  BOOST_CHECK_EXCEPTION(lexical_cast<long long>(
145  const_cast<char*>(value)), const char*, validate);
146 
147  result = "specialized - To long long - From std::string";
148 
149  BOOST_CHECK_EXCEPTION(lexical_cast<long long>(
150  std::string(value)), const char*, validate);
151 }
152 
154  unsigned char
155  , unsigned short
156  , unsigned int
157  , unsigned long>;
158 
160  test_lexical_cast_unsigned, T, test_lexical_cast_unsigned_types)
161 {
162  result = "specialized - To unsigned - From (const) char*";
163 
164  const char* value = "test";
165  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
166  value), const char*, validate);
167  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
168  const_cast<char*>(value)), const char*, validate);
169 
170  result = "specialized - To unsigned - From std::string";
171 
172  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
173  std::string(value)), const char*, validate);
174 
175 }
176 
177 BOOST_AUTO_TEST_CASE(test_lexical_cast_unsigned_long_long)
178 {
179  result = "specialized - To unsigned long long - From (const) char*";
180 
181  const char* value = "test";
182  BOOST_CHECK_EXCEPTION(lexical_cast<unsigned long long>(
183  value), const char*, validate);
184  BOOST_CHECK_EXCEPTION(lexical_cast<unsigned long long>(
185  const_cast<char*>(value)), const char*, validate);
186 
187  result = "specialized - To unsigned long long - From std::string";
188 
189  BOOST_CHECK_EXCEPTION(lexical_cast<unsigned long long>(
190  std::string(value)), const char*, validate);
191 }
192 
193 BOOST_AUTO_TEST_CASE(test_lexical_cast_bool)
194 {
195  result = "specialized - To bool - From (const) char*";
196 
197  const char* value = "test";
198  BOOST_CHECK_EXCEPTION(lexical_cast<bool>(
199  value), const char*, validate);
200  BOOST_CHECK_EXCEPTION(lexical_cast<bool>(
201  const_cast<char*>(value)), const char*, validate);
202 
203  result = "specialized - To bool - From std::string";
204 
205  BOOST_CHECK_EXCEPTION(lexical_cast<bool>(
206  std::string(value)), const char*, validate);
207 }
208 
210  float
211  , double
212  , long double>;
213 
215  test_lexical_cast_floating_point, T, test_lexical_cast_floating_point_types)
216 {
217  result = "specialized - To floating point - From (const) char*";
218 
219  const char* value = "test";
220  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
221  value), const char*, validate);
222  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
223  const_cast<char*>(value)), const char*, validate);
224 
225  result = "specialized - To floating point - From std::string";
226 
227  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
228  std::string(value)), const char*, validate);
229 }
230 
231 } // namespace test_throw
232 
233 BOOST_AUTO_TEST_CASE(test_lexical_cast_result)
234 {
235  BOOST_CHECK_EQUAL(lexical_cast<std::string>(true), "1");
236  BOOST_CHECK_EQUAL(lexical_cast<std::string>(false), "0");
237 
238  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1), "1");
239  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1u), "1");
240 
241  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1.2f), "1.2");
242  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1.2), "1.2");
243 
244  BOOST_CHECK_EQUAL(lexical_cast<int>("1"), 1);
245  BOOST_CHECK_EQUAL(lexical_cast<int>("-1"), -1);
246  BOOST_CHECK_EQUAL(lexical_cast<unsigned>("1"), 1);
247  BOOST_CHECK_EQUAL(lexical_cast<double>("1.2"), 1.2);
248  BOOST_CHECK_THROW(lexical_cast<double>("0x11"), bad_lexical_cast);
249 
250  std::string a = "01234567890123456789";
251  BOOST_CHECK_EQUAL(lexical_cast<long long>(a), 1234567890123456789ll);
252  BOOST_CHECK_THROW(lexical_cast<int>(a), bad_lexical_cast);
253  BOOST_CHECK_EQUAL(lexical_cast<double>(a), 1.23456789012345678e18);
254  BOOST_CHECK_EQUAL(lexical_cast_default<long long>(a, 0ll), 1234567890123456789ll);
255  BOOST_CHECK_EQUAL(lexical_cast_default<int>(a, 0), 0);
256  BOOST_CHECK_EQUAL(lexical_cast_default<double>(a, 0.0), 1.23456789012345678e18);
257 
258  std::string b = "99999999999999999999";
259  BOOST_CHECK_THROW(lexical_cast<long long>(b), bad_lexical_cast);
260  BOOST_CHECK_THROW(lexical_cast<int>(b), bad_lexical_cast);
261  BOOST_CHECK_EQUAL(lexical_cast<double>(b), 1e20);
262  BOOST_CHECK_EQUAL(lexical_cast_default<long long>(b, 0ll), 0ll);
263  BOOST_CHECK_EQUAL(lexical_cast_default<int>(b, 0), 0);
264  BOOST_CHECK_EQUAL(lexical_cast_default<double>(b, 0.0), 1e20);
265 }
static void validate(boost::any &v, const std::vector< std::string > &values, two_strings *, int)
New lexcical_cast header.
Standard logging facilities (interface).
#define PLAIN_LOG
Definition: log.hpp:295
std::tuple< signed char, short, int, long > test_lexical_cast_signed_types
std::tuple< unsigned char, unsigned short, unsigned int, unsigned long > test_lexical_cast_unsigned_types
std::tuple< float, double, long double > test_nomatch_types
BOOST_AUTO_TEST_CASE(test_lexical_cast_long_long)
std::tuple< bool, char, signed char, unsigned char, short, int, long, long long, unsigned short, unsigned int, unsigned long, unsigned long long > test_match_types
decltype(std::tuple_cat(test_nomatch_types{}, test_match_types{})) test_types
std::tuple< float, double, long double > test_lexical_cast_floating_point_types
BOOST_AUTO_TEST_CASE_TEMPLATE(test_lexical_cast_throw, T, test_types)
Thrown when a lexical_cast fails.
#define TEST_CASE(type_send, initializer)
BOOST_AUTO_TEST_CASE(test_lexical_cast_result)
#define a
#define b