test_flags.cpp
Go to the documentation of this file.
1 // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
2 // SPDX-License-Identifier: MIT
3 // Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #if defined(__clang__)
24 # pragma clang diagnostic push
25 #elif defined(__GNUC__)
26 # pragma GCC diagnostic push
27 #elif defined(_MSC_VER)
28 # pragma warning(push)
29 # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data.
30 #endif
31 
32 #define CATCH_CONFIG_MAIN
33 #include <catch2/catch.hpp>
34 
40 
41 #include <array>
42 #include <cctype>
43 #include <string_view>
44 #include <sstream>
45 
46 enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
47 template <>
49  static constexpr bool is_flags = true;
50 };
51 
52 enum class Numbers : int {
53  none = 0,
54  one = 1 << 1,
55  two = 1 << 2,
56  three = 1 << 3,
57  many = 1 << 30,
58 };
59 template <>
61  static constexpr bool is_flags = true;
62 };
63 
64 enum Directions : std::uint64_t {
66  Left = std::uint64_t{1} << 10,
67  Down = std::uint64_t{1} << 20,
68  Up = std::uint64_t{1} << 31,
69  Right = std::uint64_t{1} << 63,
70 };
71 template <>
73  static constexpr bool is_flags = true;
74 };
75 
76 enum number : unsigned long {
77  no_number = 0,
78  one = 1 << 1,
79  two = 1 << 2,
80  three = 1 << 3,
81  four = 1 << 4,
82 #if defined(MAGIC_ENUM_SUPPORTED_ALIASES)
83  _1 = one,
84  _2 = two,
85  _3 = three,
86  _4 = four
87 #endif
88 };
89 template <>
91  static constexpr bool is_flags = true;
92 };
93 
96 
97 using namespace magic_enum;
98 using namespace magic_enum::bitwise_operators;
99 
100 TEST_CASE("enum_cast") {
101  SECTION("string") {
102  constexpr auto cr = enum_cast<Color>("RED");
103  REQUIRE(cr.value() == Color::RED);
104  REQUIRE(enum_cast<Color&>("GREEN").value() == Color::GREEN);
105  REQUIRE(enum_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
106  REQUIRE_FALSE(enum_cast<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).has_value());
107  REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED").has_value());
108  REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED|RED").has_value());
109  REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED|None").has_value());
110  REQUIRE_FALSE(enum_cast<Color>("None").has_value());
111 
112  REQUIRE(enum_flags_cast<Color&>("GREEN").value() == Color::GREEN);
113  REQUIRE(enum_flags_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
114  REQUIRE(enum_flags_cast<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == (Color::BLUE | Color::RED));
115  REQUIRE(enum_flags_cast<Color&>("GREEN|RED").value() == (Color::GREEN | Color::RED));
116  REQUIRE(enum_flags_cast<Color&>("GREEN|RED|RED").value() == (Color::GREEN | Color::RED));
117  REQUIRE_FALSE(enum_flags_cast<Color&>("GREEN|RED|None").has_value());
118  REQUIRE_FALSE(enum_flags_cast<Color>("None").has_value());
119 
120  constexpr auto no = enum_cast<Numbers>("one");
121  REQUIRE(no.value() == Numbers::one);
122  REQUIRE(enum_cast<Numbers>("two").value() == Numbers::two);
123  REQUIRE(enum_cast<Numbers>("three").value() == Numbers::three);
124  REQUIRE(enum_cast<Numbers>("many") == Numbers::many);
125  REQUIRE_FALSE(enum_cast<Numbers>("None").has_value());
126 
127  constexpr auto dr = enum_cast<Directions>("Right");
128  REQUIRE(enum_cast<Directions&>("Up").value() == Directions::Up);
129  REQUIRE(enum_cast<const Directions>("Down").value() == Directions::Down);
130  REQUIRE(dr.value() == Directions::Right);
131  REQUIRE(enum_cast<Directions>("Left").value() == Directions::Left);
132  REQUIRE_FALSE(enum_cast<Directions>("None").has_value());
133 
134  constexpr auto nto = enum_flags_cast<number>("three|one");
135  REQUIRE(enum_cast<number>("one").value() == number::one);
136  REQUIRE(enum_cast<number>("two").value() == number::two);
137  REQUIRE(enum_cast<number>("three").value() == number::three);
138  REQUIRE(enum_cast<number>("four") == number::four);
139  REQUIRE(nto.value() == (number::three | number::one));
140  REQUIRE_FALSE(enum_cast<number>("None").has_value());
141  }
142 
143  SECTION("integer") {
145  constexpr auto cr = enum_cast<Color>(1);
146  REQUIRE(cr.value() == Color::RED);
147  REQUIRE(enum_cast<Color&>(2).value() == Color::GREEN);
148  REQUIRE(enum_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
149  REQUIRE_FALSE(enum_cast<Color>(1 | 2).has_value());
150  REQUIRE_FALSE(enum_cast<Color>(1 | 2 | 1).has_value());
151  REQUIRE_FALSE(enum_cast<Color>(1 | 2 | 8).has_value());
152  REQUIRE_FALSE(enum_cast<Color>(0).has_value());
153 
154  REQUIRE(enum_flags_cast<Color&>(2).value() == Color::GREEN);
155  REQUIRE(enum_flags_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
156  REQUIRE(enum_flags_cast<Color>(1 | 2).value() == (Color::GREEN | Color::RED));
157  REQUIRE(enum_flags_cast<Color>(1 | 2 | 1).value() == (Color::GREEN | Color::RED));
158  REQUIRE_FALSE(enum_flags_cast<Color>(1 | 2 | 8).has_value());
159  REQUIRE_FALSE(enum_flags_cast<Color>(0).has_value());
160 
161  constexpr auto no = enum_cast<Numbers>(2);
162  REQUIRE(no.value() == Numbers::one);
163  REQUIRE(enum_cast<Numbers>(4).value() == Numbers::two);
164  REQUIRE(enum_cast<Numbers>(8).value() == Numbers::three);
165  REQUIRE(enum_cast<Numbers>(1 << 30).value() == Numbers::many);
166  REQUIRE_FALSE(enum_cast<Numbers>(127).has_value());
167  REQUIRE_FALSE(enum_cast<Numbers>(0).has_value());
168 
169  constexpr auto dr = enum_cast<Directions>(std::uint64_t{1} << 63);
170  REQUIRE(enum_cast<Directions&>(std::uint64_t{1} << 31).value() == Directions::Up);
171  REQUIRE(enum_cast<const Directions>(std::uint64_t{1} << 20).value() == Directions::Down);
172  REQUIRE(dr.value() == Directions::Right);
173  REQUIRE(enum_cast<Directions>(std::uint64_t{1} << 10).value() == Directions::Left);
174  REQUIRE_FALSE(enum_cast<Directions>(0).has_value());
175 
176  constexpr auto nto = enum_flags_cast<number>(2 | 8);
177  REQUIRE(enum_cast<number>(1 << 1).value() == number::one);
178  REQUIRE(enum_cast<number>(1 << 2).value() == number::two);
179  REQUIRE(enum_cast<number>(1 << 3).value() == number::three);
180  REQUIRE(enum_cast<number>(1 << 4).value() == number::four);
181  REQUIRE(nto.value() == (number::three | number::one));
182  REQUIRE_FALSE(enum_cast<number>(0).has_value());
183  }
184 }
185 
186 TEST_CASE("enum_index") {
188  constexpr auto cr = enum_index(Color::RED);
189  Color cg = Color::GREEN;
190  REQUIRE(cr.value() == 0);
191  REQUIRE(enum_index<Color&>(cg).value() == 1);
192  REQUIRE(enum_index(cm[2]).value() == 2);
193  REQUIRE_FALSE(enum_index<Color>(Color::RED | Color::GREEN).has_value());
194  REQUIRE_FALSE(enum_index<Color>(Color::RED | Color::GREEN | Color::RED).has_value());
195  REQUIRE_FALSE(enum_index<Color>(Color::RED | Color{8}).has_value());
196  REQUIRE_FALSE(enum_index(static_cast<Color>(0)).has_value());
197 
198  constexpr auto no = enum_index(Numbers::one);
199  REQUIRE(no.value() == 0);
203  REQUIRE_FALSE(enum_index(static_cast<Numbers>(0)).has_value());
204 
205  constexpr auto dr = enum_index(Directions::Right);
207  REQUIRE(enum_index<Directions&>(dl).value() == 0);
208  REQUIRE(enum_index<const Directions>(Directions::Down).value() == 1);
210  REQUIRE(dr.value() == 3);
211  REQUIRE_FALSE(enum_index(static_cast<Directions>(0)).has_value());
212 
213  constexpr auto nto = enum_index(number::three | number::one);
218  REQUIRE_FALSE(nto.has_value());
219  REQUIRE_FALSE(enum_index(static_cast<number>(0)).has_value());
220 }
221 
222 TEST_CASE("enum_contains") {
223  SECTION("value") {
225  constexpr auto cr = enum_contains(Color::RED);
226  Color cg = Color::GREEN;
227  REQUIRE(cr);
228  REQUIRE(enum_contains<Color&>(cg));
229  REQUIRE(enum_contains(cm[2]));
230  REQUIRE_FALSE(enum_contains(static_cast<Color>(0)));
231 
232  REQUIRE(enum_flags_contains<Color&>(cg));
234  REQUIRE(enum_flags_contains<Color>(Color::RED | Color::GREEN));
235  REQUIRE(enum_flags_contains<Color>(Color::RED | Color::GREEN | Color::GREEN));
236  REQUIRE_FALSE(enum_flags_contains<Color>(Color::RED | Color{8}));
237  REQUIRE_FALSE(enum_flags_contains(static_cast<Color>(0)));
238 
239  constexpr auto no = enum_contains(Numbers::one);
240  REQUIRE(no);
244  REQUIRE_FALSE(enum_contains(static_cast<Numbers>(0)));
245 
246  constexpr auto dr = enum_contains(Directions::Right);
248  REQUIRE(enum_contains<Directions&>(dl));
249  REQUIRE(enum_contains<const Directions>(Directions::Down));
251  REQUIRE(dr);
252  REQUIRE_FALSE(enum_contains(static_cast<Directions>(0)));
253 
254  constexpr auto nto = enum_contains(number::three | number::one);
256  REQUIRE(enum_contains<number&>(number::two));
259  REQUIRE_FALSE(nto);
260  REQUIRE_FALSE(enum_contains(static_cast<number>(0)));
261 
263  }
264 
265  SECTION("integer") {
266  REQUIRE(enum_contains<Color>(1));
267  REQUIRE(enum_contains<Color&>(2));
268  REQUIRE(enum_contains<const Color>(4));
269  REQUIRE_FALSE(enum_contains<Color>(0));
270 
271  REQUIRE(enum_flags_contains<Color>(1));
272  REQUIRE(enum_flags_contains<Color&>(2));
273  REQUIRE(enum_flags_contains<Color>(4));
274  REQUIRE(enum_flags_contains<Color>(1 | 2));
275  REQUIRE(enum_flags_contains<Color>(1 | 2 | 1));
276  REQUIRE_FALSE(enum_flags_contains<Color>(1 | 2 | 8));
277  REQUIRE_FALSE(enum_flags_contains<Color>(0));
278 
279  constexpr auto no = enum_contains<Numbers>(1 << 1);
280  REQUIRE(no);
281  REQUIRE(enum_contains<Numbers>(1 << 2));
282  REQUIRE(enum_contains<Numbers>(1 << 3));
283  REQUIRE(enum_contains<Numbers>(1 << 30));
284 
285  constexpr auto dr = enum_contains<Directions&>(std::uint64_t{1} << 63);
286  REQUIRE(dr);
287  REQUIRE(enum_contains<const Directions>(std::uint64_t{1} << 10));
288  REQUIRE(enum_contains<Directions>(std::uint64_t{1} << 20));
289  REQUIRE(enum_contains<Directions>(std::uint64_t{1} << 31));
290  REQUIRE_FALSE(enum_contains<Directions>(static_cast<Directions>(0)));
291 
292  constexpr auto nto = enum_contains<number>(8 | 2);
293  REQUIRE(enum_contains<number>(1 << 1));
294  REQUIRE(enum_contains<number>(1 << 2));
295  REQUIRE(enum_contains<number>(1 << 3));
296  REQUIRE(enum_contains<number>(1 << 4));
297  REQUIRE_FALSE(enum_contains<number>(8 | 2 | 16));
298  REQUIRE_FALSE(enum_contains<number>(8 | 16 | 16));
299  REQUIRE_FALSE(nto);
300  REQUIRE_FALSE(enum_contains<number>(8 | 64));
301  REQUIRE_FALSE(enum_contains<number>(0));
302  }
303 
304  SECTION("string") {
305  constexpr auto cr = "RED";
306  REQUIRE(enum_contains<Color>(cr));
307  REQUIRE(enum_contains<Color&>("GREEN"));
308  REQUIRE(enum_contains<const Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
309  REQUIRE_FALSE(enum_contains<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
310  REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED"));
311  REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED|RED"));
312  REQUIRE_FALSE(enum_contains<Color>("GREEN|RED|None"));
313  REQUIRE_FALSE(enum_contains<Color>("None"));
314 
315  REQUIRE(enum_flags_contains<Color&>("GREEN"));
316  REQUIRE(enum_flags_contains<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
317  REQUIRE(enum_flags_contains<Color>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
318  REQUIRE(enum_flags_contains<Color>("GREEN|RED"));
319  REQUIRE(enum_flags_contains<Color>("GREEN|RED|RED"));
320  REQUIRE_FALSE(enum_flags_contains<Color>("GREEN|RED|None"));
321  REQUIRE_FALSE(enum_flags_contains<Color>("None"));
322 
323  constexpr auto no = std::string_view{"one"};
324  REQUIRE(enum_contains<Numbers>(no));
325  REQUIRE(enum_contains<Numbers>("two"));
326  REQUIRE(enum_contains<Numbers>("three"));
327  REQUIRE(enum_contains<Numbers>("many"));
328  REQUIRE_FALSE(enum_contains<Numbers>("None"));
329 
330  auto dr = std::string{"Right"};
331  REQUIRE(enum_contains<Directions&>("Up"));
332  REQUIRE(enum_contains<Directions>("Down"));
333  REQUIRE(enum_contains<const Directions>(dr));
334  REQUIRE(enum_contains<Directions>("Left"));
335  REQUIRE_FALSE(enum_contains<Directions>("None"));
336 
337  constexpr auto nto = enum_contains<number>("three|one");
338  REQUIRE(enum_contains<number>("one"));
339  REQUIRE(enum_contains<number>("two"));
340  REQUIRE(enum_contains<number>("three"));
341  REQUIRE(enum_contains<number>("four"));
342  REQUIRE_FALSE(nto);
343  REQUIRE_FALSE(enum_contains<number>("None"));
344 
345  REQUIRE(enum_flags_contains<number>("three|one"));
346  }
347 }
348 
349 TEST_CASE("enum_value") {
350  constexpr auto cr = enum_value<Color>(0);
351  REQUIRE(cr == Color::RED);
352  REQUIRE(enum_value<Color&>(1) == Color::GREEN);
353  REQUIRE(enum_value<Color>(2) == Color::BLUE);
354 
355  REQUIRE(enum_value<Color, 0>() == Color::RED);
356  REQUIRE(enum_value<Color, 1>() == Color::GREEN);
357  REQUIRE(enum_value<Color, 2>() == Color::BLUE);
358 
359  constexpr auto no = enum_value<Numbers>(0);
360  REQUIRE(no == Numbers::one);
361  REQUIRE(enum_value<Numbers>(1) == Numbers::two);
362  REQUIRE(enum_value<Numbers>(2) == Numbers::three);
363  REQUIRE(enum_value<Numbers>(3) == Numbers::many);
364 
365  REQUIRE(enum_value<Numbers, 0>() == Numbers::one);
366  REQUIRE(enum_value<Numbers, 1>() == Numbers::two);
367  REQUIRE(enum_value<Numbers, 2>() == Numbers::three);
368  REQUIRE(enum_value<Numbers, 3>() == Numbers::many);
369 
370  constexpr auto dr = enum_value<Directions>(3);
371  REQUIRE(enum_value<Directions&>(0) == Directions::Left);
372  REQUIRE(enum_value<const Directions>(1) == Directions::Down);
373  REQUIRE(enum_value<Directions>(2) == Directions::Up);
374  REQUIRE(dr == Directions::Right);
375 
376  REQUIRE(enum_value<Directions, 0>() == Directions::Left);
377  REQUIRE(enum_value<Directions, 1>() == Directions::Down);
378  REQUIRE(enum_value<Directions, 2>() == Directions::Up);
379  REQUIRE(enum_value<Directions, 3>() == Directions::Right);
380 
381  constexpr auto nt = enum_value<number>(2);
382  REQUIRE(enum_value<number>(0) == number::one);
383  REQUIRE(enum_value<number>(1) == number::two);
384  REQUIRE(nt == number::three);
385  REQUIRE(enum_value<number>(3) == number::four);
386 
387  REQUIRE(enum_value<number, 0>() == number::one);
388  REQUIRE(enum_value<number, 1>() == number::two);
389  REQUIRE(enum_value<number, 2>() == number::three);
390  REQUIRE(enum_value<number, 3>() == number::four);
391 }
392 
393 TEST_CASE("enum_values") {
394  REQUIRE(std::is_same_v<decltype(enum_values<Color>()), const std::array<Color, 3>&>);
395 
396  constexpr auto& s1 = enum_values<Color&>();
397  REQUIRE(s1 == std::array<Color, 3>{{Color::RED, Color::GREEN, Color::BLUE}});
398 
399  constexpr auto& s2 = enum_values<Numbers>();
400  REQUIRE(s2 == std::array<Numbers, 4>{{Numbers::one, Numbers::two, Numbers::three, Numbers::many}});
401 
402  constexpr auto& s3 = enum_values<const Directions>();
403  REQUIRE(s3 == std::array<Directions, 4>{{Directions::Left, Directions::Down, Directions::Up, Directions::Right}});
404 
405  constexpr auto& s4 = enum_values<number>();
406  REQUIRE(s4 == std::array<number, 4>{{number::one, number::two, number::three, number::four}});
407 }
408 
409 TEST_CASE("enum_count") {
410  constexpr auto s1 = enum_count<Color&>();
411  REQUIRE(s1 == 3);
412 
413  constexpr auto s2 = enum_count<Numbers>();
414  REQUIRE(s2 == 4);
415 
416  constexpr auto s3 = enum_count<const Directions>();
417  REQUIRE(s3 == 4);
418 
419  constexpr auto s4 = enum_count<number>();
420  REQUIRE(s4 == 4);
421 }
422 
423 TEST_CASE("enum_name") {
424  SECTION("automatic storage") {
425  constexpr Color cr = Color::RED;
426  constexpr auto cr_name = enum_name(cr);
428  Color cb = Color::BLUE;
429  REQUIRE(cr_name == "RED");
430  REQUIRE(enum_name<Color&>(cb) == "BLUE");
431  REQUIRE(enum_name(cm[1]) == "GREEN");
432  REQUIRE(enum_name(Color::RED | Color{0}) == "RED");
434  REQUIRE(enum_name(Color::RED | Color{8}).empty());
435  REQUIRE(enum_name(static_cast<Color>(0)).empty());
436 
437  constexpr Numbers no = Numbers::one;
438  constexpr auto no_name = enum_name(no);
439  REQUIRE(no_name == "one");
440  REQUIRE(enum_name(Numbers::two) == "two");
441  REQUIRE(enum_name(Numbers::three) == "three");
442  REQUIRE(enum_name(Numbers::many) == "many");
444  REQUIRE(enum_name(static_cast<Numbers>(0)).empty());
445 
446  constexpr Directions dr = Directions::Right;
447  constexpr auto dr_name = enum_name(dr);
449  REQUIRE(enum_name<Directions&>(du) == "Up");
450  REQUIRE(enum_name<const Directions>(Directions::Down) == "Down");
451  REQUIRE(dr_name == "Right");
452  REQUIRE(enum_name(Directions::Left) == "Left");
454  REQUIRE(enum_name(static_cast<Directions>(0)).empty());
455 
456  constexpr number nto = number::three | number::one;
457  constexpr auto nto_name = enum_name(nto);
458  REQUIRE(enum_name(number::one) == "one");
459  REQUIRE(enum_name(number::two) == "two");
460  REQUIRE(enum_name(number::three) == "three");
461  REQUIRE(enum_name(number::four) == "four");
462  REQUIRE(nto_name.empty());
463  REQUIRE(enum_name(static_cast<number>(0)).empty());
464  }
465 }
466 
467 TEST_CASE("enum_flags_name") {
468  constexpr Color cr = Color::RED;
469  auto cr_name = enum_flags_name(cr);
471  Color cb = Color::BLUE;
472  REQUIRE(cr_name == "RED");
473  REQUIRE(enum_flags_name<Color&>(cb) == "BLUE");
474  REQUIRE(enum_flags_name(cm[1]) == "GREEN");
475  REQUIRE(enum_flags_name(Color::RED | Color{0}) == "RED");
476  REQUIRE(enum_flags_name(Color::RED | Color::GREEN) == "RED|GREEN");
477  REQUIRE(enum_flags_name(Color::RED | Color{8}).empty());
478  REQUIRE(enum_flags_name(static_cast<Color>(0)).empty());
479 
480  constexpr Numbers no = Numbers::one;
481  auto no_name = enum_flags_name(no);
482  REQUIRE(no_name == "one");
487  REQUIRE(enum_flags_name(static_cast<Numbers>(0)).empty());
488 
489  constexpr Directions dr = Directions::Right;
490  auto dr_name = enum_flags_name(dr);
492  REQUIRE(enum_flags_name<Directions&>(du) == "Up");
493  REQUIRE(enum_flags_name<const Directions>(Directions::Down) == "Down");
494  REQUIRE(dr_name == "Right");
497  REQUIRE(enum_flags_name(static_cast<Directions>(0)).empty());
498 
499  constexpr number nto = number::three | number::one;
500  auto nto_name = enum_flags_name(nto);
505  REQUIRE(nto_name == "one|three");
506  REQUIRE(enum_flags_name(static_cast<number>(0)).empty());
507 }
508 
509 TEST_CASE("enum_names") {
510  REQUIRE(std::is_same_v<decltype(enum_names<Color>()), const std::array<std::string_view, 3>&>);
511 
512  constexpr auto& s1 = enum_names<Color&>();
513  REQUIRE(s1 == std::array<std::string_view, 3>{{"RED", "GREEN", "BLUE"}});
514 
515  constexpr auto& s2 = enum_names<Numbers>();
516  REQUIRE(s2 == std::array<std::string_view, 4>{{"one", "two", "three", "many"}});
517 
518  constexpr auto& s3 = enum_names<const Directions>();
519  REQUIRE(s3 == std::array<std::string_view, 4>{{"Left", "Down", "Up", "Right"}});
520 
521  constexpr auto& s4 = enum_names<number>();
522  REQUIRE(s4 == std::array<std::string_view, 4>{{"one", "two", "three", "four"}});
523 }
524 
525 TEST_CASE("enum_entries") {
526  REQUIRE(std::is_same_v<decltype(enum_entries<Color>()), const std::array<std::pair<Color, std::string_view>, 3>&>);
527 
528  constexpr auto& s1 = enum_entries<Color&>();
529  REQUIRE(s1 == std::array<std::pair<Color, std::string_view>, 3>{{{Color::RED, "RED"}, {Color::GREEN, "GREEN"}, {Color::BLUE, "BLUE"}}});
530 
531  constexpr auto& s2 = enum_entries<Numbers>();
532  REQUIRE(s2 == std::array<std::pair<Numbers, std::string_view>, 4>{{{Numbers::one, "one"}, {Numbers::two, "two"}, {Numbers::three, "three"}, {Numbers::many, "many"}}});
533 
534  constexpr auto& s3 = enum_entries<Directions&>();
535  REQUIRE(s3 == std::array<std::pair<Directions, std::string_view>, 4>{{{Directions::Left, "Left"}, {Directions::Down, "Down"}, {Directions::Up, "Up"}, {Directions::Right, "Right"}}});
536 
537  constexpr auto& s4 = enum_entries<number>();
538  REQUIRE(s4 == std::array<std::pair<number, std::string_view>, 4>{{{number::one, "one"}, {number::two, "two"}, {number::three, "three"}, {number::four, "four"}}});
539 }
540 
541 TEST_CASE("ostream_operators") {
542  auto test_ostream = [](auto e, std::string name) {
543  using namespace magic_enum::ostream_operators;
544  std::stringstream ss;
545  ss << e;
546  REQUIRE(ss.str() == name);
547  };
548 
549  test_ostream(std::make_optional(Color::RED), "RED");
550  test_ostream(Color::GREEN, "GREEN");
551  test_ostream(Color::BLUE, "BLUE");
552  test_ostream(Color::BLUE | Color::RED, "RED|BLUE");
553  test_ostream(Color::BLUE | Color::RED | Color::RED, "RED|BLUE");
554  test_ostream(static_cast<Color>(0), "0");
555  test_ostream(std::make_optional(static_cast<Color>(0)), "0");
556 
557  test_ostream(std::make_optional(Numbers::one), "one");
558  test_ostream(Numbers::two, "two");
559  test_ostream(Numbers::three, "three");
560  test_ostream(Numbers::many, "many");
561  test_ostream(static_cast<Numbers>(0), "0");
562  test_ostream(std::make_optional(static_cast<Numbers>(0)), "0");
563 
564  test_ostream(std::make_optional(Directions::Up), "Up");
565  test_ostream(Directions::Down, "Down");
566  test_ostream(Directions::Right, "Right");
567  test_ostream(Directions::Left, "Left");
568  test_ostream(Directions::Right | Directions::Left, "Left|Right");
569  test_ostream(static_cast<Directions>(0), "0");
570  test_ostream(std::make_optional(static_cast<Directions>(0)), "0");
571 
572  test_ostream(std::make_optional(number::one), "one");
573  test_ostream(number::two, "two");
574  test_ostream(number::three, "three");
575  test_ostream(number::four, "four");
576  test_ostream(number::four | number::one, "one|four");
577  test_ostream(static_cast<number>(0), "0");
578  test_ostream(std::make_optional(static_cast<number>(0)), "0");
579 }
580 
581 TEST_CASE("istream_operators") {
582  auto test_istream = [](const auto e, std::string name) {
583  using namespace magic_enum::istream_operators;
584  std::istringstream ss(name);
585  std::decay_t<decltype(e)> v;
586  ss >> v;
587  REQUIRE(v == e);
588  REQUIRE(ss);
589  };
590 
591  test_istream(Color::GREEN, "GREEN");
592  test_istream(Color::BLUE, "BLUE");
593  test_istream(Color::BLUE | Color::RED, "RED|BLUE");
594  test_istream(Color::BLUE | Color::RED | Color::RED, "RED|BLUE");
595 
596  test_istream(Numbers::two, "two");
597  test_istream(Numbers::three, "three");
598  test_istream(Numbers::many, "many");
599 
600  test_istream(Directions::Down, "Down");
601  test_istream(Directions::Right, "Right");
602  test_istream(Directions::Left, "Left");
603  test_istream(Directions::Right | Directions::Left, "Left|Right");
604 
605  test_istream(number::two, "two");
606  test_istream(number::three, "three");
607  test_istream(number::four, "four");
608  test_istream(number::four | number::one, "one|four");
609 }
610 
611 TEST_CASE("bitwise_operators") {
612  SECTION("operator^") {
617  }
618 
619  SECTION("operator|") {
624  }
625 
626  SECTION("operator&") {
631  }
632 
633  SECTION("operator^") {
638  }
639 
640  SECTION("operator|=") {
641  Color x1 = Color::RED;
642  x1 |= Color::BLUE;
644 
645  Numbers x2 = Numbers::one;
646  x2 |= Numbers::two;
648 
650  x3 |= Directions::Down;
652 
653  number x4 = number::one;
654  x4 |= number::two;
656  }
657 
658  SECTION("operator&=") {
659  Color x1 = Color::RED;
660  x1 &= Color::BLUE;
662 
663  Numbers x2 = Numbers::one;
664  x2 &= Numbers::two;
666 
668  x3 &= Directions::Down;
670 
671  number x4 = number::one;
672  x4 &= number::two;
674  }
675 
676  SECTION("operator^=") {
677  Color x1 = Color::RED;
678  x1 ^= Color::BLUE;
680 
681  Numbers x2 = Numbers::one;
682  x2 ^= Numbers::two;
684 
686  x3 ^= Directions::Down;
688 
689  number x4 = number::one;
690  x4 ^= number::two;
692  }
693 }
694 
695 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
696 # define MAGIC_ENUM_SUPPORTED_CONSTEXPR_FOR 1
697 #endif
698 
699 #if defined(MAGIC_ENUM_SUPPORTED_CONSTEXPR_FOR)
700 
701 // from https://artificial-mind.net/blog/2020/10/31/constexpr-for
702 template <auto Start, auto End, auto Inc, class F>
703 constexpr void constexpr_for(F&& f) {
704  if constexpr (Start < End) {
705  f(std::integral_constant<decltype(Start), Start>());
706  constexpr_for<Start + Inc, End, Inc>(f);
707  }
708 }
709 
710 template <typename E, E V>
711 struct Foo {};
712 
713 TEST_CASE("constexpr_for") {
714  constexpr_for<0, magic_enum::enum_count<Color>(), 1>([](auto i) {
715  [[maybe_unused]] Foo<Color, magic_enum::enum_value<Color, i>()> bar{};
716  });
717 }
718 
719 #endif
720 
721 #if defined(__cpp_lib_format)
722 
724 
725 TEST_CASE("format-base") {
726  REQUIRE(std::format("Test-{:~^11}.", Color::RED | Color::GREEN) == "Test-~RED|GREEN~.");
727 }
728 
729 #endif
730 
731 TEST_CASE("enum_flags_test") {
734 
740 
744 
748 }
749 
750 TEST_CASE("enum_flags_test_any") {
753 
759 
763 
768 
772 }
773 
774 TEST_CASE("enum_next_value") {
782  REQUIRE_FALSE(enum_next_value(Color::RED, -1).has_value());
783  REQUIRE_FALSE(enum_next_value(Color::RED, 10).has_value());
784 }
785 
786 TEST_CASE("enum_next_value_circular") {
803 }
804 
805 TEST_CASE("enum_prev_value") {
813  REQUIRE_FALSE(enum_prev_value(Color::BLUE, -1).has_value());
814  REQUIRE_FALSE(enum_prev_value(Color::BLUE, 10).has_value());
815 }
816 
817 TEST_CASE("enum_prev_value_circular") {
834 }
Color::GREEN
@ GREEN
Right
@ Right
Definition: test_flags.cpp:69
magic_enum::bitwise_operators
Definition: magic_enum.hpp:1464
Down
@ Down
Definition: test_flags.cpp:67
Numbers::many
@ many
magic_enum::enum_flags_contains
constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum_flags.hpp:171
s1
@ s1
Definition: test.cpp:452
magic_enum.hpp
four
@ four
Definition: test_flags.cpp:81
no_number
@ no_number
Definition: test_flags.cpp:77
magic_enum::enum_flags_name
auto enum_flags_name(E value, char_type sep=static_cast< char_type >('|')) -> detail::enable_if_t< E, string >
Definition: magic_enum_flags.hpp:67
magic_enum_utility.hpp
NoDirection
@ NoDirection
Definition: test_flags.cpp:65
magic_enum_iostream.hpp
magic_enum::enum_next_value_circular
constexpr auto enum_next_value_circular(E value, std::ptrdiff_t n=1) noexcept -> detail::enable_if_t< E, std::decay_t< E >>
Definition: magic_enum_utility.hpp:95
magic_enum::enum_flags_test_any
constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum_flags.hpp:206
magic_enum::detail::value
constexpr E value(std::size_t i) noexcept
Definition: magic_enum.hpp:679
two
@ two
Definition: test_flags.cpp:79
magic_enum::ostream_operators
Definition: magic_enum_iostream.hpp:44
magic_enum::enum_prev_value_circular
constexpr auto enum_prev_value_circular(E value, std::ptrdiff_t n=1) noexcept -> detail::enable_if_t< E, std::decay_t< E >>
Definition: magic_enum_utility.hpp:123
Numbers::one
@ one
Numbers::two
@ two
one
@ one
Definition: test_flags.cpp:78
magic_enum::enum_contains
constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum.hpp:1396
Numbers
Numbers
Definition: example_custom_name.cpp:44
REQUIRE
#define REQUIRE(...)
Definition: catch.hpp:17637
SECTION
#define SECTION(...)
Definition: catch.hpp:17677
magic_enum::enum_index
constexpr auto enum_index(E value) noexcept -> detail::enable_if_t< E, optional< std::size_t >>
Definition: magic_enum.hpp:1238
magic_enum_fuse.hpp
magic_enum::enum_flags_test
constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum_flags.hpp:197
magic_enum::istream_operators
Definition: magic_enum_iostream.hpp:78
magic_enum_flags.hpp
lt3::s3
@ s3
Color::RED
@ RED
magic_enum::customize::enum_range
Definition: magic_enum.hpp:172
catch.hpp
magic_enum::enum_name
constexpr auto enum_name() noexcept -> detail::enable_if_t< decltype(V), string_view >
Definition: magic_enum.hpp:1290
Directions
Directions
Definition: test_flags.cpp:64
Directions
Directions
Definition: test.cpp:52
lt4::s4
@ s4
s2
@ s2
Definition: test.cpp:453
REQUIRE_FALSE
#define REQUIRE_FALSE(...)
Definition: catch.hpp:17638
Color
Color
Definition: example.cpp:28
number
number
Definition: test.cpp:54
three
@ three
Definition: test_flags.cpp:80
magic_enum::enum_prev_value
constexpr auto enum_prev_value(E value, std::ptrdiff_t n=1) noexcept -> detail::enable_if_t< E, optional< std::decay_t< E >>>
Definition: magic_enum_utility.hpp:109
magic_enum::enum_next_value
constexpr auto enum_next_value(E value, std::ptrdiff_t n=1) noexcept -> detail::enable_if_t< E, optional< std::decay_t< E >>>
Definition: magic_enum_utility.hpp:81
Color::BLUE
@ BLUE
Numbers::none
@ none
magic_enum
Definition: magic_enum.hpp:126
magic_enum_format.hpp
Up
@ Up
Definition: test_flags.cpp:68
Numbers::three
@ three
number
number
Definition: test_flags.cpp:76
Left
@ Left
Definition: test_flags.cpp:66
magic_enum::enum_integer
constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t< E, underlying_type_t< E >>
Definition: magic_enum.hpp:1225
TEST_CASE
TEST_CASE("enum_cast")
Definition: test_flags.cpp:100


magic_enum
Author(s):
autogenerated on Fri Feb 21 2025 03:20:19