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