Imported Upstream version 2.99.2
[platform/upstream/libsigc++.git] / tests / test_tuple_transform_each.cc
1 /* Copyright (C) 2016 Murray Cumming
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  *  (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/
15  */
16
17 #include <cassert>
18 #include <cstdlib>
19 #include <sigc++/tuple-utils/tuple_transform_each.h>
20 #include <utility>
21 #include <functional>
22
23 template <class T_element_from>
24 class transform_to_string {
25 public:
26   static decltype(auto)
27   transform(T_element_from& from) {
28     return std::to_string(from);
29   }
30 };
31
32 // In these tests, t_expected has elements all of the same type.
33 void
34 test_tuple_transform_each_same_types() {
35   {
36     auto t_original = std::make_tuple(1, 2, 3);
37     auto t_transformed =
38       sigc::internal::tuple_transform_each<transform_to_string>(t_original);
39     auto t_expected =
40       std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
41
42     static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
43       "unexpected tuple_transform_each()ed tuple size.");
44
45     assert(std::get<0>(t_transformed) == "1");
46     assert(std::get<1>(t_transformed) == "2");
47     assert(std::get<2>(t_transformed) == "3");
48
49     static_assert(
50       std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
51       "unexpected transform_each()ed tuple type");
52   }
53
54   {
55     auto t_original = std::make_tuple(1, (double)2.1f, 3);
56     auto t_transformed =
57       sigc::internal::tuple_transform_each<transform_to_string>(t_original);
58     auto t_expected =
59       std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
60
61     static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
62       "unexpected tuple_transform_each()ed tuple size.");
63
64     assert(std::get<0>(t_transformed) == "1");
65     assert(std::get<1>(t_transformed).substr(0, 3) == "2.1");
66     assert(std::get<2>(t_transformed) == "3");
67
68     static_assert(
69       std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
70       "unexpected transform_each()ed tuple type");
71   }
72 }
73
74 // The general template declaration.
75 // We then provide specializations for each type,
76 // so we can test having a different return value for each T_element_from type.
77 template <class T_element_from>
78 class transform_to_something;
79
80 // An int will be converted to a std::string:
81 template <>
82 class transform_to_something<int> {
83 public:
84   static std::string
85   transform(int& from) {
86     return std::to_string(from);
87   }
88 };
89
90 // A double will be converted to a char:
91 template <>
92 class transform_to_something<double> {
93 public:
94   static char
95   transform(double& from) {
96     return std::to_string(from)[0];
97   }
98 };
99
100 // A std::string will be converted to an int:
101 template <>
102 class transform_to_something<std::string> {
103 public:
104   static int
105   transform(std::string& from) {
106     return std::stoi(from);
107   }
108 };
109
110 // In these tests, t_expected has elements of different types.
111 void
112 test_tuple_transform_each_multiple_types() {
113   auto t_original = std::make_tuple(1, (double)2.1f, std::string("3"));
114   auto t_transformed =
115     sigc::internal::tuple_transform_each<transform_to_something>(t_original);
116   auto t_expected = std::make_tuple(std::string("1"), '2', 3);
117
118   static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
119     "unexpected tuple_transform_each()ed tuple size.");
120
121   assert(std::get<0>(t_transformed) == "1");
122   assert(std::get<1>(t_transformed) == '2');
123   assert(std::get<2>(t_transformed) == 3);
124
125   static_assert(
126     std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
127     "unexpected transform_each()ed tuple type");
128 }
129
130 template <class T_element_from>
131 class transform_each_nonconst {
132 public:
133   static int
134   transform(T_element_from& from) {
135     from *= 2;
136     // Or, for instance, call a non-const method on from.
137
138     return from * 10;
139   }
140 };
141
142 void
143 test_tuple_transform_each_nonconst() {
144   auto t = std::make_tuple(1, 2, 3);
145   auto t_transformed =
146     sigc::internal::tuple_transform_each<transform_each_nonconst>(t);
147
148   // Check that t was changed (from * 2):
149   assert(std::get<0>(t) == 2);
150   assert(std::get<1>(t) == 4);
151   assert(std::get<2>(t) == 6);
152
153   // Check that t_transformed has the expected values ( from * 2 * 10):
154   assert(std::get<0>(t_transformed) == 20);
155   assert(std::get<1>(t_transformed) == 40);
156   assert(std::get<2>(t_transformed) == 60);
157 }
158
159 void
160 test_tuple_transform_each_stdref() {
161   int a = 1;
162   int b = 2;
163   int c = 3;
164   auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
165   auto t_transformed =
166     sigc::internal::tuple_transform_each<transform_to_string>(t_original);
167   auto t_expected =
168     std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
169
170   static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
171     "unexpected tuple_transform_each()ed tuple size.");
172
173   assert(std::get<0>(t_transformed) == "1");
174   assert(std::get<1>(t_transformed) == "2");
175   assert(std::get<2>(t_transformed) == "3");
176
177   static_assert(
178     std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
179     "unexpected transform_each()ed tuple type");
180 }
181
182
183 //This can only be used via std::ref(), for instance.
184 //Any attempt to copy or move it, should cause a compiler error.
185 class NonCopyable {
186 public:
187   explicit NonCopyable(int val)
188   : m_val(val)
189   {}
190   
191   int get_val() const {
192     return m_val;
193   }
194
195   NonCopyable(const NonCopyable& src) = delete;
196   NonCopyable& operator=(const NonCopyable& src) = delete;
197   
198   NonCopyable(NonCopyable&& src) = delete;
199   NonCopyable& operator=(NonCopyable&& src) = delete;
200
201 private:
202   int m_val;
203 };
204
205
206 template <class T_element_from>
207 class transform_noncopyable_to_string {
208 public:
209   static decltype(auto)
210   transform(T_element_from&& from) {
211     return std::to_string(from.get_val());
212   }
213 };
214
215 void
216 test_tuple_transform_each_stdref_non_copyable() {
217   NonCopyable a(1);
218   NonCopyable b(2);
219   NonCopyable c(3);
220   auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
221   auto t_transformed =
222     sigc::internal::tuple_transform_each<transform_noncopyable_to_string>(t_original);
223   auto t_expected =
224     std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
225
226   static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
227     "unexpected tuple_transform_each()ed tuple size.");
228
229   assert(std::get<0>(t_transformed) == "1");
230   assert(std::get<1>(t_transformed) == "2");
231   assert(std::get<2>(t_transformed) == "3");
232
233   static_assert(
234     std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
235     "unexpected transform_each()ed tuple type");
236 }
237
238 static std::string correct_sequence_output;
239
240 template <class T_element_from>
241 class transform_each_correct_sequence {
242 public:
243   static decltype(auto)
244   transform(int from) {
245     correct_sequence_output += std::to_string(from);
246     return std::to_string(from);
247   }
248 };
249
250 void
251 test_tuple_transform_each_correct_sequence() {
252   correct_sequence_output.clear();
253   auto t = std::make_tuple(1, 2, 3);
254   sigc::internal::tuple_transform_each<transform_each_correct_sequence>(t);
255   //std::cout << "correct_sequence_output: " << correct_sequence_output << std::endl;
256   assert(correct_sequence_output == "123");
257 }
258
259 void
260 test_tuple_transform_each_empty_tuple() {
261   auto t = std::tuple<>();
262   sigc::internal::tuple_transform_each<transform_to_string>(t);
263 }
264
265 // The general template declaration.
266 // We then provide specializations for each type,
267 // so we can test having a different return value for each T_element_from type.
268 template <class T_element_from>
269 class transform_as_constexpr_to_something;
270
271 // An int will be converted to a char:
272 template <>
273 class transform_as_constexpr_to_something<int> {
274 public:
275   constexpr
276   static
277   char
278   transform(int from) {
279     return 'a' + from;
280   }
281 };
282
283 // A double will be converted to an int:
284 template <>
285 class transform_as_constexpr_to_something<const double> {
286 public:
287   constexpr
288   static
289   int
290   transform(double from) {
291     return (int)from;
292   }
293 };
294
295 /* TODO: See the comment in main().
296 constexpr
297 void
298 test_tuple_transform_each_constexpr() {
299   constexpr auto t_original = std::make_tuple(1, (double)2.1f);
300   constexpr auto t_transformed =
301     sigc::internal::tuple_transform_each<transform_as_constexpr_to_something>(t_original);
302   constexpr auto t_expected = std::make_tuple('b', 2);
303
304   static_assert(std::tuple_size<decltype(t_transformed)>::value == 2,
305     "unexpected tuple_transform_each()ed tuple size.");
306
307   assert(std::get<0>(t_transformed) == 'b');
308   assert(std::get<1>(t_transformed) == 2);
309
310   static_assert(
311     std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
312     "unexpected transform_each()ed tuple type");
313 }
314 */
315
316 int
317 main() {
318   test_tuple_transform_each_same_types();
319   test_tuple_transform_each_multiple_types();
320
321   test_tuple_transform_each_nonconst();
322
323   test_tuple_transform_each_stdref();
324   test_tuple_transform_each_stdref_non_copyable();
325
326   test_tuple_transform_each_correct_sequence();
327
328   test_tuple_transform_each_empty_tuple();
329
330   // g++ 5.2.1 gives this error:
331   //   error: accessing uninitialized member ‘std::tuple<char>::<anonymous>’
332   // though it works with clang++.
333   // TODO: Try it with a newer g++.
334   //test_tuple_transform_each_constexpr();
335
336   return EXIT_SUCCESS;
337 }