The Battle for Wesnoth  1.19.16+dev
test_lexical_cast.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2025
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_bool_types = std::tuple<
40  /* note Wesnoth's coding style doesn't allow w_char so ignore them. */
41  bool>;
42 
43 using test_integral_types = std::tuple<
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_floating_point_types = std::tuple<float, double, long double>;
55 
56 using test_match_types = decltype(std::tuple_cat(test_bool_types{}, test_integral_types{}));
57 using test_nomatch_types = decltype(std::tuple_cat(test_floating_point_types{}));
58 using test_types = decltype(std::tuple_cat(test_nomatch_types{}, test_match_types{}));
59 
61 
62 namespace {
63 
64  std::string result;
65 
66 bool validate(const char* str)
67 {
68  if(str != result) {
69  PLAIN_LOG << "Received " << str << '\n'
70  << "Expected " << result << '\n';
71  return false;
72  } else {
73  return true;
74  }
75 }
76 
77 template<typename Test, typename... Types>
78 constexpr bool contains_type(std::tuple<Types...>)
79 {
80  return (std::is_same_v<Test, Types> || ...);
81 }
82 
83 } // namespace
84 
85 #define TEST_CASE(type_send) \
86  { \
87  type_send val = value; \
88  \
89  BOOST_CHECK_EXCEPTION( \
90  lexical_cast<std::string>(val), const char*, validate); \
91  }
92 
93 BOOST_AUTO_TEST_CASE_TEMPLATE(test_lexical_cast_throw, T, test_types)
94 {
95  T value = T();
96 
97  result = "specialized - To std::string - From arithmetic";
98 
99 
100  TEST_CASE(T);
101  TEST_CASE(const T);
102 
103  TEST_CASE(T&);
104  TEST_CASE(const T&);
105 }
106 
107 #undef TEST_CASE
108 
110  test_lexical_arithmetic_signed, T, test_arithmetic_types)
111 {
112  result = "specialized - To arithmetic - From string";
113 
114  const char* value = "test";
115  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
116  value), const char*, validate);
117  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
118  const_cast<char*>(value)), const char*, validate);
119  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
120  std::string(value)), const char*, validate);
121  BOOST_CHECK_EXCEPTION(lexical_cast<T>(
122  std::string_view(value)), const char*, validate);
123 }
124 
125 BOOST_AUTO_TEST_CASE(test_lexical_cast_bool)
126 {
127  result = "specialized - To bool - From string";
128 
129  const char* value = "test";
130  BOOST_CHECK_EXCEPTION(lexical_cast<bool>(
131  value), const char*, validate);
132  BOOST_CHECK_EXCEPTION(lexical_cast<bool>(
133  const_cast<char*>(value)), const char*, validate);
134  BOOST_CHECK_EXCEPTION(lexical_cast<bool>(
135  std::string(value)), const char*, validate);
136  BOOST_CHECK_EXCEPTION(lexical_cast<bool>(
137  std::string_view(value)), const char*, validate);
138 }
139 
140 } // namespace test_throw
141 
142 
143 BOOST_AUTO_TEST_CASE(test_lexical_cast_result)
144 {
145  BOOST_CHECK_EQUAL(lexical_cast<std::string>(true), "1");
146  BOOST_CHECK_EQUAL(lexical_cast<std::string>(false), "0");
147 
148  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1), "1");
149  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1u), "1");
150 
151  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1.2f), "1.2");
152  BOOST_CHECK_EQUAL(lexical_cast<std::string>(1.2), "1.2");
153 
154  BOOST_CHECK_EQUAL(lexical_cast<int>("1"), 1);
155  BOOST_CHECK_EQUAL(lexical_cast<int>("-1"), -1);
156  BOOST_CHECK_EQUAL(lexical_cast<unsigned>("1"), 1);
157  BOOST_CHECK_EQUAL(lexical_cast<double>("1.2"), 1.2);
158 
159  // The unit [effect] code uses this a lot
160  BOOST_CHECK_EQUAL(lexical_cast_default<int>("80%"), 80);
161 
162  BOOST_CHECK_EQUAL(lexical_cast<double>("0x11"), 0);
163 
164  std::string a = "01234567890123456789";
165  BOOST_CHECK_EQUAL(lexical_cast<long long>(a), 1234567890123456789ll);
166  BOOST_CHECK_THROW(lexical_cast<int>(a), bad_lexical_cast);
167  BOOST_CHECK_EQUAL(lexical_cast<double>(a), 1.23456789012345678e18);
168  BOOST_CHECK_EQUAL(lexical_cast_default<long long>(a, 0ll), 1234567890123456789ll);
169  BOOST_CHECK_EQUAL(lexical_cast_default<int>(a, 0), 0);
170  BOOST_CHECK_EQUAL(lexical_cast_default<double>(a, 0.0), 1.23456789012345678e18);
171 
172  std::string b = "99999999999999999999";
173  BOOST_CHECK_THROW(lexical_cast<long long>(b), bad_lexical_cast);
174  BOOST_CHECK_THROW(lexical_cast<int>(b), bad_lexical_cast);
175  BOOST_CHECK_EQUAL(lexical_cast<double>(b), 1e20);
176  BOOST_CHECK_EQUAL(lexical_cast_default<long long>(b, 0ll), 0ll);
177  BOOST_CHECK_EQUAL(lexical_cast_default<int>(b, 0), 0);
178  BOOST_CHECK_EQUAL(lexical_cast_default<double>(b, 0.0), 1e20);
179 }
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:296
std::tuple< char, signed char, unsigned char, short, int, long, long long, unsigned short, unsigned int, unsigned long, unsigned long long > test_integral_types
BOOST_AUTO_TEST_CASE(test_lexical_cast_bool)
decltype(std::tuple_cat(test_integral_types{}, test_floating_point_types{})) test_arithmetic_types
decltype(std::tuple_cat(test_bool_types{}, test_integral_types{})) test_match_types
std::tuple< float, double, long double > test_floating_point_types
decltype(std::tuple_cat(test_floating_point_types{})) test_nomatch_types
decltype(std::tuple_cat(test_nomatch_types{}, test_match_types{})) test_types
std::tuple< bool > test_bool_types
BOOST_AUTO_TEST_CASE_TEMPLATE(test_lexical_cast_throw, T, test_types)
Thrown when a lexical_cast fails.
#define TEST_CASE(type_send)
BOOST_AUTO_TEST_CASE(test_lexical_cast_result)
#define b