test.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 #define CATCH_CONFIG_MAIN
24 #include <catch2/catch.hpp>
25 
26 #define MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM
27 #define MAGIC_ENUM_RANGE_MIN -120
28 #define MAGIC_ENUM_RANGE_MAX 120
33 
34 #include <array>
35 #include <cctype>
36 #include <string_view>
37 #include <sstream>
38 
39 enum class Color { RED = -12, GREEN = 7, BLUE = 15 };
40 template <>
41 constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<Color>(Color value) noexcept {
42  switch (value) {
43  case Color::RED:
44  return "red";
45  default:
46  return default_tag;
47  }
48 }
49 
50 enum class Numbers : int { one = 1, two, three, many = 127 };
51 
52 enum Directions { Up = 85, Down = -42, Right = 120, Left = -120 };
53 
54 enum number : unsigned long {
55  one = 100,
56  two = 200,
57  three = 300,
58  four = 400,
59 #if defined(MAGIC_ENUM_SUPPORTED_ALIASES)
60  _1 = one,
61  _2 = two,
62  _3 = three,
63  _4 = four
64 #endif
65 };
66 template <>
68  static constexpr int min = 100;
69  static constexpr int max = 300;
70 };
71 
72 enum class crc_hack {
74 };
75 
76 enum class crc_hack_2 {
79 };
80 
81 enum class MaxUsedAsInvalid : std::uint8_t {
82  ONE,
83  TWO = 63,
84  INVALID = std::numeric_limits<std::uint8_t>::max()
85 };
86 template <>
88  static constexpr int min = 0;
89  static constexpr int max = 64;
90 };
91 
92 enum class Binary : bool {
93  ONE,
94  TWO
95 };
96 template <>
98  static constexpr int min = 0;
99  static constexpr int max = 64;
100 };
101 
102 enum class BoolTest : bool { Yay, Nay };
103 
104 using namespace magic_enum;
105 
106 static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
107 
108 TEST_CASE("enum_cast") {
109  SECTION("string") {
110  constexpr auto cr = enum_cast<Color>("red");
111  REQUIRE(cr.value() == Color::RED);
112  REQUIRE(enum_cast<Color&>("GREEN").value() == Color::GREEN);
113  REQUIRE(enum_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
114  REQUIRE_FALSE(enum_cast<Color>("None").has_value());
115 
116  constexpr auto no = enum_cast<Numbers>("one");
117  REQUIRE(no.value() == Numbers::one);
118  REQUIRE(enum_cast<Numbers>("two").value() == Numbers::two);
119  REQUIRE(enum_cast<Numbers>("three").value() == Numbers::three);
120  REQUIRE_FALSE(enum_cast<Numbers>("many").has_value());
121  REQUIRE_FALSE(enum_cast<Numbers>("None").has_value());
122 
123  constexpr auto dr = enum_cast<Directions>("Right");
124  REQUIRE(enum_cast<Directions&>("Up").value() == Directions::Up);
125  REQUIRE(enum_cast<const Directions>("Down").value() == Directions::Down);
126  REQUIRE(dr.value() == Directions::Right);
127  REQUIRE(enum_cast<Directions>("Left").value() == Directions::Left);
128  REQUIRE_FALSE(enum_cast<Directions>("None").has_value());
129 
130  constexpr auto dr2 = enum_cast<Directions>("RIGHT", case_insensitive);
131  REQUIRE(dr2.value() == Directions::Right);
132  REQUIRE(enum_cast<Directions&>("up", case_insensitive).value() == Directions::Up);
133  REQUIRE(enum_cast<const Directions>("dOwN", case_insensitive).value() == Directions::Down);
134  REQUIRE_FALSE(enum_cast<Directions>("Left-", case_insensitive).has_value());
135 
136  constexpr auto nt = enum_cast<number>("three");
137  REQUIRE(enum_cast<number>("one").value() == number::one);
138  REQUIRE(enum_cast<number>("two").value() == number::two);
139  REQUIRE(nt.value() == number::three);
140  REQUIRE_FALSE(enum_cast<number>("four").has_value());
141  REQUIRE_FALSE(enum_cast<number>("None").has_value());
142 
143  REQUIRE(enum_cast<crc_hack>("b5a7b602ab754d7ab30fb42c4fb28d82").has_value());
144  REQUIRE_FALSE(enum_cast<crc_hack>("d19f2e9e82d14b96be4fa12b8a27ee9f").has_value());
145 
146  constexpr auto crc = enum_cast<crc_hack_2>("b5a7b602ab754d7ab30fb42c4fb28d82");
148  REQUIRE(enum_cast<crc_hack_2>("d19f2e9e82d14b96be4fa12b8a27ee9f").value() == crc_hack_2::d19f2e9e82d14b96be4fa12b8a27ee9f);
149 
150  REQUIRE(enum_cast<BoolTest>("Nay").has_value());
151  }
152 
153  SECTION("integer") {
155  constexpr auto cr = enum_cast<Color>(-12);
156  REQUIRE(cr.value() == Color::RED);
157  REQUIRE(enum_cast<Color&>(7).value() == Color::GREEN);
158  REQUIRE(enum_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
159  REQUIRE_FALSE(enum_cast<Color>(0).has_value());
160 
161  constexpr auto no = enum_cast<Numbers>(1);
162  REQUIRE(no.value() == Numbers::one);
163  REQUIRE(enum_cast<Numbers>(2).value() == Numbers::two);
164  REQUIRE(enum_cast<Numbers>(3).value() == Numbers::three);
165  REQUIRE_FALSE(enum_cast<Numbers>(127).has_value());
166  REQUIRE_FALSE(enum_cast<Numbers>(0).has_value());
167 
168  constexpr auto dr = enum_cast<Directions>(120);
169  REQUIRE(enum_cast<Directions&>(85).value() == Directions::Up);
170  REQUIRE(enum_cast<const Directions>(-42).value() == Directions::Down);
171  REQUIRE(dr.value() == Directions::Right);
172  REQUIRE(enum_cast<Directions>(-120).value() == Directions::Left);
173  REQUIRE_FALSE(enum_cast<Directions>(0).has_value());
174 
175  constexpr auto nt = enum_cast<number>(300);
176  REQUIRE(enum_cast<number>(100).value() == number::one);
177  REQUIRE(enum_cast<number>(200).value() == number::two);
178  REQUIRE(nt.value() == number::three);
179  REQUIRE_FALSE(enum_cast<number>(400).has_value());
180  REQUIRE_FALSE(enum_cast<number>(0).has_value());
181 
182  REQUIRE(enum_cast<BoolTest>(false).has_value());
183  REQUIRE(enum_cast<BoolTest>(0).has_value());
184  }
185 }
186 
187 TEST_CASE("enum_integer") {
189  constexpr auto cr = enum_integer(Color::RED);
190  Color cg = Color::GREEN;
191  REQUIRE(cr == -12);
192  REQUIRE(enum_integer<Color&>(cg) == 7);
193  REQUIRE(enum_integer(cm[2]) == 15);
194  REQUIRE(enum_integer(static_cast<Color>(0)) == 0);
195 
196  constexpr auto no = enum_integer(Numbers::one);
197  REQUIRE(no == 1);
201  REQUIRE(enum_integer(static_cast<Numbers>(0)) == 0);
202 
203  constexpr auto dr = enum_integer(Directions::Right);
205  REQUIRE(enum_integer<Directions&>(dl) == -120);
206  REQUIRE(enum_integer<const Directions>(Directions::Down) == -42);
208  REQUIRE(dr == 120);
209  REQUIRE(enum_integer(static_cast<Directions>(0)) == 0);
210 
211  constexpr auto nt = enum_integer(number::three);
214  REQUIRE(nt == 300);
216  REQUIRE(enum_integer(static_cast<number>(0)) == 0);
217 
219 }
220 
221 TEST_CASE("enum_index") {
223  constexpr auto cr = enum_index(Color::RED);
224  Color cg = Color::GREEN;
225  REQUIRE(cr.value() == 0);
226  REQUIRE(enum_index<Color::RED>() == 0);
227  REQUIRE(enum_index<Color&>(cg).value() == 1);
228  REQUIRE(enum_index(cm[2]).value() == 2);
229  REQUIRE_FALSE(enum_index(static_cast<Color>(0)).has_value());
230 
231  constexpr auto no = enum_index(Numbers::one);
232  REQUIRE(no.value() == 0);
233  REQUIRE(enum_index<Numbers::one>() == 0);
236  REQUIRE_FALSE(enum_index(Numbers::many).has_value());
237  REQUIRE_FALSE(enum_index(static_cast<Numbers>(0)).has_value());
238 
239  constexpr auto dr = enum_index(Directions::Right);
241  REQUIRE(enum_index<Directions::Left>() == 0);
242  REQUIRE(enum_index<Directions&>(dl).value() == 0);
243  REQUIRE(enum_index<const Directions>(Directions::Down).value() == 1);
245  REQUIRE(dr.value() == 3);
246  REQUIRE_FALSE(enum_index(static_cast<Directions>(0)).has_value());
247 
248  constexpr auto nt = enum_index(number::three);
249  REQUIRE(enum_index<number::one>() == 0);
252  REQUIRE(nt.value() == 2);
253  REQUIRE_FALSE(enum_index(number::four).has_value());
254  REQUIRE_FALSE(enum_index(static_cast<number>(0)).has_value());
255 
256  REQUIRE(enum_index<BoolTest::Yay>() == 0);
257 }
258 
259 TEST_CASE("enum_contains") {
260  SECTION("value") {
262  constexpr auto cr = enum_contains(Color::RED);
263  Color cg = Color::GREEN;
264  REQUIRE(cr);
265  REQUIRE(enum_contains<Color&>(cg));
266  REQUIRE(enum_contains(cm[2]));
267  REQUIRE_FALSE(enum_contains(static_cast<Color>(0)));
268 
269  constexpr auto no = enum_contains(Numbers::one);
270  REQUIRE(no);
274  REQUIRE_FALSE(enum_contains(static_cast<Numbers>(0)));
275 
276  constexpr auto dr = enum_contains(Directions::Right);
278  REQUIRE(enum_contains<Directions&>(dl));
279  REQUIRE(enum_contains<const Directions>(Directions::Down));
281  REQUIRE(dr);
282  REQUIRE_FALSE(enum_contains(static_cast<Directions>(0)));
283 
284  constexpr auto nt = enum_contains(number::three);
286  REQUIRE(enum_contains<number&>(number::two));
287  REQUIRE(nt);
289  REQUIRE_FALSE(enum_contains(static_cast<number>(0)));
290 
292  }
293 
294  SECTION("integer") {
295  REQUIRE(enum_contains<Color>(-12));
296  REQUIRE(enum_contains<Color&>(7));
297  REQUIRE(enum_contains<Color>(15));
298  REQUIRE_FALSE(enum_contains<Color>(42));
299  REQUIRE_FALSE(enum_contains<Color>(-120));
300  REQUIRE_FALSE(enum_contains<Color>(0));
301 
302  constexpr auto no = enum_integer(Numbers::one);
303  REQUIRE(enum_contains<Numbers>(no));
304  REQUIRE(enum_contains<Numbers>(enum_integer(Numbers::two)));
305  REQUIRE(enum_contains<Numbers>(enum_integer(Numbers::three)));
306  REQUIRE_FALSE(enum_contains<Numbers>(enum_integer(Numbers::many)));
307 
308  constexpr auto dr = enum_integer(Directions::Right);
309  REQUIRE(enum_contains<Directions&>(dr));
310  REQUIRE(enum_contains<const Directions>(Directions::Down));
311  REQUIRE(enum_contains<Directions>(Directions::Up));
312  REQUIRE_FALSE(enum_contains<Directions>(static_cast<Directions>(0)));
313 
314  constexpr auto nt = enum_contains<number>(number::three);
315  REQUIRE(enum_contains<number>(number::one));
316  REQUIRE(enum_contains<number>(100));
317  REQUIRE(enum_contains<number>(200));
318  REQUIRE(enum_contains<number>(300));
319  REQUIRE(enum_contains<number>(number::two));
320  REQUIRE(nt);
321  REQUIRE_FALSE(enum_contains<number>(number::four));
322  REQUIRE_FALSE(enum_contains<number>(111));
323  REQUIRE_FALSE(enum_contains<number>(0));
324 
325  REQUIRE(enum_contains<BoolTest>(false));
326  REQUIRE(enum_contains<BoolTest>(0));
327  }
328 
329  SECTION("string") {
330  constexpr auto cr = "red";
331  REQUIRE(enum_contains<Color>(cr));
332  REQUIRE(enum_contains<Color&>("GREEN"));
333  REQUIRE(enum_contains<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
334  REQUIRE_FALSE(enum_contains<Color>("None"));
335 
336  constexpr auto no = std::string_view{"one"};
337  REQUIRE(enum_contains<Numbers>(no));
338  REQUIRE(enum_contains<Numbers>("two"));
339  REQUIRE(enum_contains<Numbers>("three"));
340  REQUIRE_FALSE(enum_contains<Numbers>("many"));
341  REQUIRE_FALSE(enum_contains<Numbers>("None"));
342 
343  auto dr = std::string{"Right"};
344  REQUIRE(enum_contains<Directions&>("Up"));
345  REQUIRE(enum_contains<Directions>("Down"));
346  REQUIRE(enum_contains<const Directions>(dr));
347  REQUIRE(enum_contains<Directions>("Left"));
348  REQUIRE_FALSE(enum_contains<Directions>("None"));
349 
350  auto dr2 = std::string{"RIGHT"};
351  REQUIRE(enum_contains<const Directions>(dr2, case_insensitive));
352  REQUIRE(enum_contains<Directions&>("up", case_insensitive));
353  REQUIRE(enum_contains<Directions>("dOwN", case_insensitive));
354  REQUIRE_FALSE(enum_contains<Directions>("Left-", case_insensitive));
355 
356  constexpr auto nt = enum_contains<number>("three");
357  REQUIRE(enum_contains<number>("one"));
358  REQUIRE(enum_contains<number>("two"));
359  REQUIRE(nt);
360  REQUIRE_FALSE(enum_contains<number>("four"));
361  REQUIRE_FALSE(enum_contains<number>("None"));
362 
363  REQUIRE(enum_contains<BoolTest>("Yay"));
364  }
365 }
366 
367 TEST_CASE("enum_value") {
368  constexpr auto cr = enum_value<Color>(0);
369  REQUIRE(cr == Color::RED);
370  REQUIRE(enum_value<Color&>(1) == Color::GREEN);
371  REQUIRE(enum_value<Color>(2) == Color::BLUE);
372 
373  REQUIRE(enum_value<Color, 0>() == Color::RED);
374  REQUIRE(enum_value<Color, 1>() == Color::GREEN);
375  REQUIRE(enum_value<Color, 2>() == Color::BLUE);
376 
377  constexpr auto no = enum_value<Numbers>(0);
378  REQUIRE(no == Numbers::one);
379  REQUIRE(enum_value<Numbers>(1) == Numbers::two);
380  REQUIRE(enum_value<Numbers>(2) == Numbers::three);
381 
382  REQUIRE(enum_value<Numbers, 0>() == Numbers::one);
383  REQUIRE(enum_value<Numbers, 1>() == Numbers::two);
384  REQUIRE(enum_value<Numbers, 2>() == Numbers::three);
385 
386  constexpr auto dr = enum_value<Directions>(3);
387  REQUIRE(enum_value<Directions&>(0) == Directions::Left);
388  REQUIRE(enum_value<const Directions>(1) == Directions::Down);
389  REQUIRE(enum_value<Directions>(2) == Directions::Up);
390  REQUIRE(dr == Directions::Right);
391 
392  REQUIRE(enum_value<Directions, 0>() == Directions::Left);
393  REQUIRE(enum_value<Directions, 1>() == Directions::Down);
394  REQUIRE(enum_value<Directions, 2>() == Directions::Up);
395  REQUIRE(enum_value<Directions, 3>() == Directions::Right);
396 
397  constexpr auto nt = enum_value<number>(2);
398  REQUIRE(enum_value<number>(0) == number::one);
399  REQUIRE(enum_value<number>(1) == number::two);
400  REQUIRE(nt == number::three);
401 
402  REQUIRE(enum_value<number, 0>() == number::one);
403  REQUIRE(enum_value<number, 1>() == number::two);
404  REQUIRE(enum_value<number, 2>() == number::three);
405 
406  REQUIRE(enum_value<BoolTest>(0) == BoolTest::Yay);
407  REQUIRE(enum_value<BoolTest, 0>() == BoolTest::Yay);
408 }
409 
410 TEST_CASE("enum_values") {
411  REQUIRE(std::is_same_v<decltype(enum_values<Color>()), const std::array<Color, 3>&>);
412 
413  constexpr auto& s1 = enum_values<Color&>();
414  REQUIRE(s1 == std::array<Color, 3>{{Color::RED, Color::GREEN, Color::BLUE}});
415 
416  constexpr auto& s2 = enum_values<Numbers>();
417  REQUIRE(s2 == std::array<Numbers, 3>{{Numbers::one, Numbers::two, Numbers::three}});
418 
419  constexpr auto& s3 = enum_values<const Directions>();
420  REQUIRE(s3 == std::array<Directions, 4>{{Directions::Left, Directions::Down, Directions::Up, Directions::Right}});
421 
422  constexpr auto& s4 = enum_values<number>();
423  REQUIRE(s4 == std::array<number, 3>{{number::one, number::two, number::three}});
424 
425  constexpr auto& s5 = enum_values<Binary>();
426  REQUIRE(s5 == std::array<Binary, 2>{{Binary::ONE, Binary::TWO}});
427 
428  constexpr auto& s6 = enum_values<MaxUsedAsInvalid>();
429  REQUIRE(s6 == std::array<MaxUsedAsInvalid, 2>{{MaxUsedAsInvalid::ONE, MaxUsedAsInvalid::TWO}});
430 }
431 
432 TEST_CASE("enum_count") {
433  constexpr auto s1 = enum_count<Color&>();
434  REQUIRE(s1 == 3);
435 
436  constexpr auto s2 = enum_count<Numbers>();
437  REQUIRE(s2 == 3);
438 
439  constexpr auto s3 = enum_count<const Directions>();
440  REQUIRE(s3 == 4);
441 
442  constexpr auto s4 = enum_count<number>();
443  REQUIRE(s4 == 3);
444 
445  constexpr auto s5 = enum_count<Binary>();
446  REQUIRE(s5 == 2);
447 
448  constexpr auto s6 = enum_count<MaxUsedAsInvalid>();
449  REQUIRE(s6 == 2);
450 }
451 
453 enum lt2 : unsigned { s2, loooooooooooooooooooong2 };
455 enum class lt4 : unsigned { s4, loooooooooooooooooooong4 };
456 class foo1 {
457  public:
458  enum class lt5 { s5, loooooooooooooooooooong5 };
459 };
460 class foo2 {
461  public:
462  enum lt6 { s6, loooooooooooooooooooong6 };
463 };
464 
465 namespace boo1 {
467 enum lt2 : unsigned { s2, loooooooooooooooooooong2 };
469 enum class lt4 : unsigned { s4, loooooooooooooooooooong4 };
470 class foo1 {
471  public:
472  enum class lt5 { s5, loooooooooooooooooooong5 };
473 };
474 class foo2 {
475  public:
476  enum lt6 { s6, loooooooooooooooooooong6 };
477 };
478 } // namespace boo1
479 
480 namespace boo2 {
481 namespace boo3 {
483 enum lt2 : unsigned { s2, loooooooooooooooooooong2 };
485 enum class lt4 : unsigned { s4, loooooooooooooooooooong4 };
486 class foo1 {
487  public:
488  enum class lt5 { s5, loooooooooooooooooooong5 };
489 };
490 class foo2 {
491  public:
492  enum lt6 { s6, loooooooooooooooooooong6 };
493 };
494 } // namespace boo2::boo3
495 } // namespace boo2
496 
497 namespace {
498 enum a_lt1 { s1, loooooooooooooooooooong1 };
499 enum a_lt2 : unsigned { s2, loooooooooooooooooooong2 };
500 enum class a_lt3 { s3, loooooooooooooooooooong3 };
501 enum class a_lt4 : unsigned { s4, loooooooooooooooooooong4 };
502 class a_foo1 {
503  public:
504  enum class a_lt5 { s5, loooooooooooooooooooong5 };
505 };
506 class a_foo2 {
507  public:
508  enum a_lt6 { s6, loooooooooooooooooooong6 };
509 };
510 } // namespace
511 
512 enum class LargeNumbers {
513  First = -1024,
514  Second = 1024
515 };
516 
517 TEST_CASE("enum_name") {
518  SECTION("automatic storage") {
519  constexpr Color cr = Color::RED;
520  constexpr auto cr_name = enum_name(cr);
522  Color cb = Color::BLUE;
523  REQUIRE(cr_name == "red");
524  REQUIRE(enum_name<Color&>(cb) == "BLUE");
525  REQUIRE(enum_name<as_flags<false>>(cm[1]) == "GREEN");
526  REQUIRE(enum_name<as_common<true>>(cm[1]) == "GREEN");
527  REQUIRE(enum_name<as_flags<false>>(static_cast<Color>(0)).empty());
528 
529  constexpr Numbers no = Numbers::one;
530  constexpr auto no_name = enum_name(no);
531  REQUIRE(no_name == "one");
532  REQUIRE(enum_name<Numbers, as_flags<false>>(Numbers::two) == "two");
533  REQUIRE(enum_name<as_flags<false>, Numbers>(Numbers::three) == "three");
534  REQUIRE(enum_name(Numbers::many).empty());
535  REQUIRE(enum_name(static_cast<Numbers>(0)).empty());
536 
537  constexpr Directions dr = Directions::Right;
538  constexpr auto dr_name = enum_name(dr);
540  REQUIRE(enum_name<Directions&>(du) == "Up");
541  REQUIRE(enum_name<const Directions>(Directions::Down) == "Down");
542  REQUIRE(dr_name == "Right");
543  REQUIRE(enum_name(Directions::Left) == "Left");
544  REQUIRE(enum_name(static_cast<Directions>(0)).empty());
545 
546  constexpr number nt = number::three;
547  constexpr auto nt_name = enum_name(nt);
548  REQUIRE(enum_name(number::one) == "one");
549  REQUIRE(enum_name(number::two) == "two");
550  REQUIRE(nt_name == "three");
551  REQUIRE(enum_name(number::four).empty());
552  REQUIRE(enum_name(static_cast<number>(0)).empty());
553 
555 
556  REQUIRE(enum_name(lt1::s1) == "s1");
557  REQUIRE(enum_name(lt1::loooooooooooooooooooong1) == "loooooooooooooooooooong1");
558  REQUIRE(enum_name(lt2::s2) == "s2");
559  REQUIRE(enum_name(lt2::loooooooooooooooooooong2) == "loooooooooooooooooooong2");
560  REQUIRE(enum_name(lt3::s3) == "s3");
561  REQUIRE(enum_name(lt3::loooooooooooooooooooong3) == "loooooooooooooooooooong3");
562  REQUIRE(enum_name(lt4::s4) == "s4");
563  REQUIRE(enum_name(lt4::loooooooooooooooooooong4) == "loooooooooooooooooooong4");
564  REQUIRE(enum_name(foo1::lt5::s5) == "s5");
565  REQUIRE(enum_name(foo1::lt5::loooooooooooooooooooong5) == "loooooooooooooooooooong5");
566  REQUIRE(enum_name(foo2::s6) == "s6");
567  REQUIRE(enum_name(foo2::loooooooooooooooooooong6) == "loooooooooooooooooooong6");
568 
569  REQUIRE_FALSE(enum_name((foo1::lt5)12).size());
570  REQUIRE_FALSE(enum_name((foo2::lt6)12).size());
571 
572  REQUIRE(enum_name(boo1::lt1::s1) == "s1");
573  REQUIRE(enum_name(boo1::lt1::loooooooooooooooooooong1) == "loooooooooooooooooooong1");
574  REQUIRE(enum_name(boo1::lt2::s2) == "s2");
575  REQUIRE(enum_name(boo1::lt2::loooooooooooooooooooong2) == "loooooooooooooooooooong2");
576  REQUIRE(enum_name(boo1::lt3::s3) == "s3");
577  REQUIRE(enum_name(boo1::lt3::loooooooooooooooooooong3) == "loooooooooooooooooooong3");
578  REQUIRE(enum_name(boo1::lt4::s4) == "s4");
579  REQUIRE(enum_name(boo1::lt4::loooooooooooooooooooong4) == "loooooooooooooooooooong4");
581  REQUIRE(enum_name(boo1::foo1::lt5::loooooooooooooooooooong5) == "loooooooooooooooooooong5");
582  REQUIRE(enum_name(boo1::foo2::s6) == "s6");
583  REQUIRE(enum_name(boo1::foo2::loooooooooooooooooooong6) == "loooooooooooooooooooong6");
584 
587 
589  REQUIRE(enum_name(boo2::boo3::lt1::loooooooooooooooooooong1) == "loooooooooooooooooooong1");
591  REQUIRE(enum_name(boo2::boo3::lt2::loooooooooooooooooooong2) == "loooooooooooooooooooong2");
593  REQUIRE(enum_name(boo2::boo3::lt3::loooooooooooooooooooong3) == "loooooooooooooooooooong3");
595  REQUIRE(enum_name(boo2::boo3::lt4::loooooooooooooooooooong4) == "loooooooooooooooooooong4");
597  REQUIRE(enum_name(boo2::boo3::foo1::lt5::loooooooooooooooooooong5) == "loooooooooooooooooooong5");
599  REQUIRE(enum_name(boo2::boo3::foo2::loooooooooooooooooooong6) == "loooooooooooooooooooong6");
600 
603 
604  REQUIRE(enum_name(a_lt1::s1) == "s1");
605  REQUIRE(enum_name(a_lt1::loooooooooooooooooooong1) == "loooooooooooooooooooong1");
606  REQUIRE(enum_name(a_lt2::s2) == "s2");
607  REQUIRE(enum_name(a_lt2::loooooooooooooooooooong2) == "loooooooooooooooooooong2");
608  REQUIRE(enum_name(a_lt3::s3) == "s3");
609  REQUIRE(enum_name(a_lt3::loooooooooooooooooooong3) == "loooooooooooooooooooong3");
610  REQUIRE(enum_name(a_lt4::s4) == "s4");
611  REQUIRE(enum_name(a_lt4::loooooooooooooooooooong4) == "loooooooooooooooooooong4");
612  REQUIRE(enum_name(a_foo1::a_lt5::s5) == "s5");
613  REQUIRE(enum_name(a_foo1::a_lt5::loooooooooooooooooooong5) == "loooooooooooooooooooong5");
614  REQUIRE(enum_name(a_foo2::s6) == "s6");
615  REQUIRE(enum_name(a_foo2::loooooooooooooooooooong6) == "loooooooooooooooooooong6");
616 
617  REQUIRE_FALSE(enum_name((a_foo1::a_lt5)12).size());
618  REQUIRE_FALSE(enum_name((a_foo2::a_lt6)12).size());
619  }
620 
621  SECTION("static storage") {
622  constexpr Color cr = Color::RED;
623  constexpr auto cr_name = enum_name<cr>();
624  constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
625  REQUIRE(cr_name == "red");
626  REQUIRE(enum_name<Color::BLUE>() == "BLUE");
627  REQUIRE(enum_name<cm[1]>() == "GREEN");
628 
629  constexpr Numbers no = Numbers::one;
630  constexpr auto no_name = enum_name<no>();
631  REQUIRE(no_name == "one");
632  REQUIRE(enum_name<Numbers::two>() == "two");
633  REQUIRE(enum_name<Numbers::three>() == "three");
634  REQUIRE(enum_name<Numbers::many>() == "many");
635 
636  constexpr Directions dr = Directions::Right;
637  constexpr auto dr_name = enum_name<dr>();
638  REQUIRE(enum_name<Directions::Up>() == "Up");
639  REQUIRE(enum_name<Directions::Down>() == "Down");
640  REQUIRE(dr_name == "Right");
641  REQUIRE(enum_name<Directions::Left>() == "Left");
642 
643  constexpr number nt = number::three;
644  constexpr auto nt_name = enum_name<nt>();
645  REQUIRE(enum_name<number::one>() == "one");
646  REQUIRE(enum_name<number::two>() == "two");
647  REQUIRE(nt_name == "three");
648  REQUIRE(enum_name<number::four>() == "four");
649 
650  REQUIRE(enum_name<Binary::ONE>() == "ONE");
651  REQUIRE(enum_name<MaxUsedAsInvalid::ONE>() == "ONE");
652  }
653 
654  SECTION("empty if the value is out of range") {
655  const auto ln_value = GENERATE(LargeNumbers::First, LargeNumbers::Second);
656  const auto ln_name = enum_name(ln_value);
657 
658  REQUIRE(ln_name.empty());
659  }
660 }
661 
662 TEST_CASE("enum_names") {
663  REQUIRE(std::is_same_v<decltype(enum_names<Color>()), const std::array<std::string_view, 3>&>);
664 
665  constexpr auto& s1 = enum_names<Color&>();
666  REQUIRE(s1 == std::array<std::string_view, 3>{{"red", "GREEN", "BLUE"}});
667 
668  constexpr auto& s2 = enum_names<Numbers>();
669  REQUIRE(s2 == std::array<std::string_view, 3>{{"one", "two", "three"}});
670 
671  constexpr auto& s3 = enum_names<const Directions>();
672  REQUIRE(s3 == std::array<std::string_view, 4>{{"Left", "Down", "Up", "Right"}});
673 
674  constexpr auto& s4 = enum_names<number>();
675  REQUIRE(s4 == std::array<std::string_view, 3>{{"one", "two", "three"}});
676 }
677 
678 TEST_CASE("enum_entries") {
679  REQUIRE(std::is_same_v<decltype(enum_entries<Color>()), const std::array<std::pair<Color, std::string_view>, 3>&>);
680 
681  constexpr auto& s1 = enum_entries<Color&>();
682  REQUIRE(s1 == std::array<std::pair<Color, std::string_view>, 3>{{{Color::RED, "red"}, {Color::GREEN, "GREEN"}, {Color::BLUE, "BLUE"}}});
683 
684  constexpr auto& s2 = enum_entries<Numbers>();
685  REQUIRE(s2 == std::array<std::pair<Numbers, std::string_view>, 3>{{{Numbers::one, "one"}, {Numbers::two, "two"}, {Numbers::three, "three"}}});
686 
687  constexpr auto& s3 = enum_entries<Directions&>();
688  REQUIRE(s3 == std::array<std::pair<Directions, std::string_view>, 4>{{{Directions::Left, "Left"}, {Directions::Down, "Down"}, {Directions::Up, "Up"}, {Directions::Right, "Right"}}});
689 
690  constexpr auto& s4 = enum_entries<number>();
691  REQUIRE(s4 == std::array<std::pair<number, std::string_view>, 3>{{{number::one, "one"}, {number::two, "two"}, {number::three, "three"}}});
692 }
693 
694 TEST_CASE("ostream_operators") {
695  auto test_ostream = [](auto e, std::string name) {
696  using namespace magic_enum::ostream_operators;
697  std::stringstream ss;
698  ss << e;
699  REQUIRE(ss);
700  REQUIRE(ss.str() == name);
701  };
702 
703  test_ostream(std::make_optional(Color::RED), "red");
704  test_ostream(Color::GREEN, "GREEN");
705  test_ostream(Color::BLUE, "BLUE");
706  test_ostream(static_cast<Color>(0), "0");
707  test_ostream(std::make_optional(static_cast<Color>(0)), "0");
708 
709  test_ostream(std::make_optional(Numbers::one), "one");
710  test_ostream(Numbers::two, "two");
711  test_ostream(Numbers::three, "three");
712  test_ostream(Numbers::many, "127");
713  test_ostream(static_cast<Numbers>(0), "0");
714  test_ostream(std::make_optional(static_cast<Numbers>(0)), "0");
715 
716  test_ostream(std::make_optional(Directions::Up), "Up");
717  test_ostream(Directions::Down, "Down");
718  test_ostream(Directions::Right, "Right");
719  test_ostream(Directions::Left, "Left");
720  test_ostream(static_cast<Directions>(0), "0");
721  test_ostream(std::make_optional(static_cast<Directions>(0)), "0");
722 
723  test_ostream(std::make_optional(number::one), "one");
724  test_ostream(number::two, "two");
725  test_ostream(number::three, "three");
726  test_ostream(number::four, "400");
727  test_ostream(static_cast<number>(0), "0");
728  test_ostream(std::make_optional(static_cast<number>(0)), "0");
729 }
730 
731 TEST_CASE("istream_operators") {
732  auto test_istream = [](const auto e, std::string name) {
733  using namespace magic_enum::istream_operators;
734  std::istringstream ss(name);
735  std::decay_t<decltype(e)> v;
736  ss >> v;
737  REQUIRE(ss);
738  REQUIRE(v == e);
739  };
740 
741  test_istream(Color::GREEN, "GREEN");
742  test_istream(Color::BLUE, "BLUE");
743 
744  test_istream(Numbers::two, "two");
745  test_istream(Numbers::three, "three");
746 
747  test_istream(Directions::Down, "Down");
748  test_istream(Directions::Right, "Right");
749  test_istream(Directions::Left, "Left");
750 
751  test_istream(number::two, "two");
752  test_istream(number::three, "three");
753 }
754 
755 TEST_CASE("bitwise_operators") {
756  using namespace magic_enum::bitwise_operators;
757 
758  SECTION("operator^") {
763  }
764 
765  SECTION("operator|") {
770  }
771 
772  SECTION("operator&") {
777  }
778 
779  SECTION("operator^") {
784  }
785 
786  SECTION("operator|=") {
787  Color x1 = Color::RED;
788  x1 |= Color::BLUE;
790 
791  Numbers x2 = Numbers::one;
792  x2 |= Numbers::two;
794 
796  x3 |= Directions::Down;
798 
799  number x4 = number::one;
800  x4 |= number::two;
802  }
803 
804  SECTION("operator&=") {
805  Color x1 = Color::RED;
806  x1 &= Color::BLUE;
808 
809  Numbers x2 = Numbers::one;
810  x2 &= Numbers::two;
812 
814  x3 &= Directions::Down;
816 
817  number x4 = number::one;
818  x4 &= number::two;
820  }
821 
822  SECTION("operator^=") {
823  Color x1 = Color::RED;
824  x1 ^= Color::BLUE;
826 
827  Numbers x2 = Numbers::one;
828  x2 ^= Numbers::two;
830 
832  x3 ^= Directions::Down;
834 
835  number x4 = number::one;
836  x4 ^= number::two;
838  }
839 }
840 
841 TEST_CASE("type_traits") {
842  REQUIRE_FALSE(is_unscoped_enum_v<Color>);
843  REQUIRE_FALSE(is_unscoped_enum_v<Numbers>);
844  REQUIRE(is_unscoped_enum_v<Directions>);
845  REQUIRE(is_unscoped_enum_v<number>);
846 
847  REQUIRE(is_scoped_enum_v<Color>);
848  REQUIRE(is_scoped_enum_v<Numbers>);
849  REQUIRE_FALSE(is_scoped_enum_v<Directions>);
850  REQUIRE_FALSE(is_scoped_enum_v<number>);
851 }
852 
853 TEST_CASE("enum_type_name") {
854  REQUIRE(enum_type_name<Color&>() == "Color");
855  REQUIRE(enum_type_name<const Numbers>() == "Numbers");
856  REQUIRE(enum_type_name<const Directions&>() == "Directions");
857  REQUIRE(enum_type_name<number>() == "number");
858 
859  REQUIRE(enum_type_name<lt1>() == "lt1");
860  REQUIRE(enum_type_name<lt2>() == "lt2");
861  REQUIRE(enum_type_name<lt3>() == "lt3");
862  REQUIRE(enum_type_name<lt4>() == "lt4");
863  REQUIRE(enum_type_name<foo1::lt5>() == "lt5");
864  REQUIRE(enum_type_name<foo2::lt6>() == "lt6");
865  REQUIRE(enum_type_name<decltype(foo2::s6)>() == "lt6");
866 
867  REQUIRE(enum_type_name<boo1::lt1>() == "lt1");
868  REQUIRE(enum_type_name<boo1::lt2>() == "lt2");
869  REQUIRE(enum_type_name<boo1::lt3>() == "lt3");
870  REQUIRE(enum_type_name<boo1::lt4>() == "lt4");
871  REQUIRE(enum_type_name<boo1::foo1::lt5>() == "lt5");
872  REQUIRE(enum_type_name<boo1::foo2::lt6>() == "lt6");
873  REQUIRE(enum_type_name<decltype(boo1::foo2::s6)>() == "lt6");
874 
875  REQUIRE(enum_type_name<boo2::boo3::lt1>() == "lt1");
876  REQUIRE(enum_type_name<boo2::boo3::lt2>() == "lt2");
877  REQUIRE(enum_type_name<boo2::boo3::lt3>() == "lt3");
878  REQUIRE(enum_type_name<boo2::boo3::lt4>() == "lt4");
879  REQUIRE(enum_type_name<boo2::boo3::foo1::lt5>() == "lt5");
880  REQUIRE(enum_type_name<boo2::boo3::foo2::lt6>() == "lt6");
881  REQUIRE(enum_type_name<decltype(boo2::boo3::foo2::s6)>() == "lt6");
882 
883  REQUIRE(enum_type_name<a_lt1>() == "a_lt1");
884  REQUIRE(enum_type_name<a_lt2>() == "a_lt2");
885  REQUIRE(enum_type_name<a_lt3>() == "a_lt3");
886  REQUIRE(enum_type_name<a_lt4>() == "a_lt4");
887  REQUIRE(enum_type_name<a_foo1::a_lt5>() == "a_lt5");
888  REQUIRE(enum_type_name<a_foo2::a_lt6>() == "a_lt6");
889  REQUIRE(enum_type_name<decltype(a_foo2::s6)>() == "a_lt6");
890 }
891 
892 #if defined(MAGIC_ENUM_SUPPORTED_ALIASES)
893 TEST_CASE("aliases") {
894  REQUIRE(enum_count<number>() == 3);
895 
896  REQUIRE(enum_name(number::one) == enum_name(number::_1));
897  REQUIRE(enum_name(number::two) == enum_name(number::_2));
898  REQUIRE(enum_name(number::three) == enum_name(number::_3));
899  REQUIRE(enum_name(number::four) == enum_name(number::_4));
900 
901  REQUIRE(enum_integer(number::one) == enum_integer(number::_1));
902  REQUIRE(enum_integer(number::two) == enum_integer(number::_2));
905 
906  REQUIRE_FALSE(enum_cast<number>("_1").has_value());
907  REQUIRE_FALSE(enum_cast<number>("_2").has_value());
908  REQUIRE_FALSE(enum_cast<number>("_3").has_value());
909  REQUIRE_FALSE(enum_cast<number>("_4").has_value());
910 }
911 #endif
912 
913 TEST_CASE("extrema") {
914  enum class BadColor : std::uint64_t {
915  RED,
916  GREEN,
917  YELLOW,
918  // The value NONE is ignored (out of range).
919  // However, it affects the value of min_v. When reflected_min_v was incorrect,
920  // the presence of NONE caused miv_v to be equal to -1, which was then cast to unsigned,
921  // leading to a value of 18446744073709551615 (numeric_limit_max of uint64_t).
922  NONE = std::numeric_limits<std::uint64_t>::max()
923  };
924 
925  REQUIRE(magic_enum::enum_name<BadColor>(BadColor::NONE).empty());
926  REQUIRE_FALSE(enum_cast<BadColor>(std::numeric_limits<std::uint64_t>::max()).has_value());
927  REQUIRE_FALSE(magic_enum::enum_contains<BadColor>(std::numeric_limits<std::uint64_t>::max()));
928  REQUIRE_FALSE(magic_enum::enum_contains<BadColor>(BadColor::NONE));
929 
930  SECTION("min") {
932  REQUIRE(magic_enum::detail::reflected_min<BadColor, as_common<>>() == 0);
933  REQUIRE(magic_enum::detail::min_v<BadColor, as_common<>> == 0);
934 
937  REQUIRE(magic_enum::detail::min_v<Color, as_common<>> == -12);
938 
941  REQUIRE(magic_enum::detail::min_v<Numbers, as_common<>> == 1);
942 
945  REQUIRE(magic_enum::detail::min_v<Directions, as_common<>> == -120);
946 
948  REQUIRE(magic_enum::detail::reflected_min<number, as_common<>>() == 100);
949  REQUIRE(magic_enum::detail::min_v<number, as_common<>> == 100);
950 
951  REQUIRE(magic_enum::detail::reflected_min<Binary, as_common<>>() == 0);
952  REQUIRE(magic_enum::detail::min_v<Binary, as_common<>> == false);
953 
956  }
957 
958  SECTION("max") {
961  REQUIRE(magic_enum::detail::max_v<BadColor, as_common<>> == 2);
962 
965  REQUIRE(magic_enum::detail::max_v<Color, as_common<>> == 15);
966 
969  REQUIRE(magic_enum::detail::max_v<Numbers, as_common<>> == 3);
970 
973  REQUIRE(magic_enum::detail::max_v<Directions, as_common<>> == 120);
974 
976  REQUIRE(magic_enum::detail::reflected_max<number, as_common<>>() == 300);
977  REQUIRE(magic_enum::detail::max_v<number, as_common<>> == 300);
978 
979  REQUIRE(magic_enum::detail::reflected_max<Binary, as_common<>>() == 1);
980  REQUIRE(magic_enum::detail::max_v<Binary, as_common<>> == true);
981 
984  }
985 }
986 
987 TEST_CASE("cmp_less") {
989 
990  constexpr std::uint64_t uint64_t_min = std::numeric_limits<std::uint64_t>::min();
991  constexpr std::uint32_t uint32_t_min = std::numeric_limits<std::uint32_t>::min();
992  constexpr std::uint32_t uint32_t_max = std::numeric_limits<std::uint32_t>::max();
993  constexpr std::uint64_t uint64_t_max = std::numeric_limits<std::uint64_t>::max();
994 
995  constexpr std::int64_t int64_t_min = std::numeric_limits<std::int64_t>::min();
996  constexpr std::int32_t int32_t_min = std::numeric_limits<std::int32_t>::min();
997  constexpr std::int32_t int32_t_max = std::numeric_limits<std::int32_t>::max();
998  constexpr std::int64_t int64_t_max = std::numeric_limits<std::int64_t>::max();
999 
1000  // Also testing with offset to avoid corner cases.
1001  // Two variables to avoid hidden casts:
1002  constexpr std::int64_t offset_int64_t = 17;
1003  constexpr std::int32_t offset_int32_t = 17;
1004 
1005  SECTION("same signedness") {
1006  REQUIRE(cmp_less(-5, -3));
1007  REQUIRE(cmp_less(27U, 49U));
1008  }
1009 
1010  SECTION("same signedness, different width") {
1011  REQUIRE(cmp_less(uint32_t_max, uint64_t_max));
1012  REQUIRE_FALSE(cmp_less(uint64_t_max, uint32_t_max));
1013  REQUIRE(cmp_less(int64_t_min, int32_t_min));
1014  REQUIRE_FALSE(cmp_less(int32_t_min, int64_t_min));
1015  REQUIRE(cmp_less(int64_t_min + offset_int64_t, int32_t_min + offset_int32_t));
1016  REQUIRE_FALSE(cmp_less(int32_t_min + offset_int32_t, int64_t_min + offset_int64_t));
1017  }
1018 
1019  SECTION("left signed, right unsigned") {
1020  REQUIRE(cmp_less(-5, 3U));
1021  REQUIRE(cmp_less(3, 5U));
1022  }
1023 
1024  SECTION("left signed, right unsigned, different width") {
1025  REQUIRE(cmp_less(int32_t_max, uint64_t_max));
1026  REQUIRE_FALSE(cmp_less(int64_t_max, uint32_t_max));
1027  REQUIRE(cmp_less(int32_t_min, uint64_t_min));
1028  REQUIRE(cmp_less(int64_t_min, uint32_t_min));
1029  REQUIRE(cmp_less(int32_t_max - offset_int32_t, uint64_t_max));
1030  REQUIRE_FALSE(cmp_less(int64_t_max - offset_int64_t, uint32_t_max));
1031  REQUIRE(cmp_less(int32_t_min + offset_int32_t, uint64_t_min));
1032  REQUIRE(cmp_less(int64_t_min + offset_int64_t, uint32_t_min));
1033  }
1034 
1035  SECTION("left unsigned, right signed") {
1036  REQUIRE_FALSE(cmp_less(3U, -5));
1037  REQUIRE(cmp_less(3U, 5));
1038  }
1039 
1040  SECTION("left unsigned, right signed, different width") {
1041  REQUIRE(cmp_less(uint32_t_max, int64_t_max));
1042  REQUIRE_FALSE(cmp_less(uint64_t_max, int32_t_max));
1043  REQUIRE_FALSE(cmp_less(uint32_t_min, int64_t_min));
1044  REQUIRE_FALSE(cmp_less(uint64_t_min, int32_t_min));
1045  REQUIRE(cmp_less(uint32_t_max, int64_t_max - offset_int32_t));
1046  REQUIRE_FALSE(cmp_less(uint64_t_max, int32_t_max - offset_int64_t));
1047  REQUIRE_FALSE(cmp_less(uint32_t_min, int64_t_min + offset_int32_t));
1048  REQUIRE_FALSE(cmp_less(uint64_t_min, int32_t_min + offset_int64_t));
1049  }
1050 
1051  SECTION("bool, right") {
1052  REQUIRE(cmp_less(true, 5));
1053  REQUIRE(cmp_less(false, 1));
1054  REQUIRE_FALSE(cmp_less(false, -1));
1055  }
1056 
1057  SECTION("left, bool") {
1058  REQUIRE_FALSE(cmp_less(5, true));
1059  REQUIRE_FALSE(cmp_less(1, false));
1060  REQUIRE(cmp_less(-1, false));
1061  }
1062 }
1063 
1064 template <Color C>
1065 constexpr std::string_view DoWork() {
1066  return "default";
1067 }
1068 
1069 template <>
1070 constexpr std::string_view DoWork<Color::GREEN>() {
1071  return "override";
1072 }
1073 
1074 TEST_CASE("enum_for_each") {
1075  SECTION("no return type") {
1077  enum_for_each<Color>([&sum](auto val) {
1078  constexpr underlying_type_t<Color> v = enum_integer(val());
1079  sum += v;
1080  });
1081  REQUIRE(sum == 10);
1082  }
1083 
1084  SECTION("same return type") {
1085  constexpr auto workResults = enum_for_each<Color>([](auto val) {
1086  return DoWork<val>();
1087  });
1088  REQUIRE(workResults == std::array<std::string_view, 3>{"default", "override", "default"});
1089  }
1090 
1091  SECTION("different return type") {
1092  constexpr auto colorInts = enum_for_each<Color>([](auto val) {
1093  return val;
1094  });
1095 
1096  REQUIRE(std::is_same_v<std::remove_const_t<decltype(colorInts)>,
1097  std::tuple<enum_constant<Color::RED>,
1100  }
1101 }
1102 
1103 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
1104 # define MAGIC_ENUM_SUPPORTED_CONSTEXPR_FOR 1
1105 #endif
1106 
1107 #if defined(MAGIC_ENUM_SUPPORTED_CONSTEXPR_FOR)
1108 
1109 // from https://artificial-mind.net/blog/2020/10/31/constexpr-for
1110 template <auto Start, auto End, auto Inc, class F>
1111 constexpr void constexpr_for(F&& f) {
1112  if constexpr (Start < End) {
1113  f(std::integral_constant<decltype(Start), Start>());
1114  constexpr_for<Start + Inc, End, Inc>(f);
1115  }
1116 }
1117 
1118 template <typename E, E V>
1119 struct Foo {};
1120 
1121 TEST_CASE("constexpr_for") {
1122  constexpr_for<0, magic_enum::enum_count<Color>(), 1>([](auto i) {
1123  [[maybe_unused]] Foo<Color, magic_enum::enum_value<Color, i>()> bar{};
1124  });
1125 
1126  constexpr_for<0, magic_enum::enum_count<Numbers>(), 1>([](auto i) {
1127  [[maybe_unused]] Foo<Numbers, magic_enum::enum_value<Numbers, i>()> bar{};
1128  });
1129 }
1130 
1131 #if defined(_MSC_VER)
1132 # pragma warning(push)
1133 # pragma warning(disable : 4064)
1134 #endif
1135 
1136 static int switch_case_2d(Color color, Directions direction) {
1137  switch (enum_fuse(color, direction).value()) {
1138  case enum_fuse(Color::RED, Directions::Up).value():
1139  return 1;
1140  case enum_fuse(Color::BLUE, Directions::Down).value():
1141  return 2;
1142  default:
1143  return 0;
1144  }
1145 }
1146 
1147 enum class Index { zero = 0, one = 1, two = 2 };
1148 
1149 static int switch_case_3d(Color color, Directions direction, Index index) {
1150  switch (enum_fuse(color, direction, index).value()) {
1151  case enum_fuse(Color::RED, Directions::Up, Index::zero).value():
1152  return 1;
1153  case enum_fuse(Color::BLUE, Directions::Up, Index::zero).value():
1154  return 2;
1155  default:
1156  return 0;
1157  }
1158 }
1159 
1160 #if defined(_MSC_VER)
1161 # pragma warning(pop)
1162 #endif
1163 
1164 TEST_CASE("multdimensional-switch-case") {
1165  REQUIRE(switch_case_2d(Color::RED, Directions::Up) == 1);
1166  REQUIRE(switch_case_2d(Color::RED, Directions::Down) == 0);
1167  REQUIRE(switch_case_2d(Color::BLUE, Directions::Up) == 0);
1168  REQUIRE(switch_case_2d(Color::BLUE, Directions::Down) == 2);
1169  REQUIRE(switch_case_3d(Color::RED, Directions::Up, Index::zero) == 1);
1170  REQUIRE(switch_case_3d(Color::BLUE, Directions::Up, Index::zero) == 2);
1171  REQUIRE(switch_case_3d(Color::BLUE, Directions::Up, Index::one) == 0);
1172  REQUIRE(switch_case_3d(Color::BLUE, Directions::Up, Index::two) == 0);
1173 }
1174 
1175 #endif
1176 
1177 #if defined(__cpp_lib_format)
1178 
1179 #include <format>
1181 
1182 TEST_CASE("format-base") {
1183  REQUIRE(std::format("{}", Color::RED) == "red");
1184  REQUIRE(std::format("{}", Color{0}) == "0");
1185 }
1186 
1187 #endif
1188 
1189 TEST_CASE("enum_next_value") {
1197  REQUIRE_FALSE(enum_next_value(Color::RED, -1).has_value());
1198  REQUIRE_FALSE(enum_next_value(Color::RED, 10).has_value());
1199 }
1200 
1201 TEST_CASE("enum_next_value_circular") {
1218 }
1219 
1220 TEST_CASE("enum_prev_value") {
1228  REQUIRE_FALSE(enum_prev_value(Color::BLUE, -1).has_value());
1229  REQUIRE_FALSE(enum_prev_value(Color::BLUE, 10).has_value());
1230 }
1231 
1232 TEST_CASE("enum_prev_value_circular") {
1249 }
1250 
1251 TEST_CASE("valid_enum") {
1252  //enum Forward1;
1253  enum Forward2 : uint32_t;
1254  enum class Forward3;
1255  enum class Forward4 : uint32_t;
1256  enum Empty1 {};
1257  enum Empty2 : uint32_t {};
1258  enum class Empty3 {};
1259  enum class Empty4 : uint32_t {};
1260 
1261  //REQUIRE(magic_enum::detail::is_reflected_v<Forward1, as_flags<true>>);
1262  //REQUIRE(magic_enum::detail::is_reflected_v<Forward1, as_flags<false>>);
1263  REQUIRE(magic_enum::detail::is_reflected_v<Forward2, as_flags<true>>);
1264  REQUIRE(magic_enum::detail::is_reflected_v<Forward2, as_flags<false>>);
1265  REQUIRE(magic_enum::detail::is_reflected_v<Forward3, as_flags<true>>);
1266  REQUIRE(magic_enum::detail::is_reflected_v<Forward3, as_flags<false>>);
1267  REQUIRE(magic_enum::detail::is_reflected_v<Forward4, as_flags<true>>);
1268  REQUIRE(magic_enum::detail::is_reflected_v<Forward4, as_flags<false>>);
1269  REQUIRE(magic_enum::detail::is_reflected_v<Empty1, as_flags<true>>);
1270  REQUIRE(magic_enum::detail::is_reflected_v<Empty1, as_flags<false>>);
1271  REQUIRE(magic_enum::detail::is_reflected_v<Empty2, as_flags<true>>);
1272  REQUIRE(magic_enum::detail::is_reflected_v<Empty2, as_flags<false>>);
1273  REQUIRE(magic_enum::detail::is_reflected_v<Empty3, as_flags<true>>);
1274  REQUIRE(magic_enum::detail::is_reflected_v<Empty3, as_flags<false>>);
1275  REQUIRE(magic_enum::detail::is_reflected_v<Empty4, as_flags<true>>);
1276  REQUIRE(magic_enum::detail::is_reflected_v<Empty4, as_flags<false>>);
1277 }
1278 
1279 TEST_CASE("enum_reflected") {
1280  REQUIRE(enum_reflected<number>(number::one));
1281  REQUIRE(enum_reflected<number>(number::three));
1282  REQUIRE_FALSE(enum_reflected<number>(number::four));
1283  REQUIRE(enum_reflected<number>(100));
1284  REQUIRE(enum_reflected<number>(101));
1285  REQUIRE(enum_reflected<number>(234));
1286  REQUIRE(enum_reflected<number>(300));
1287  REQUIRE_FALSE(enum_reflected<number>(400));
1288  REQUIRE_FALSE(enum_reflected<number>(500));
1289 }
Color::GREEN
@ GREEN
magic_enum::customize::enum_range::max
static constexpr int max
Definition: magic_enum.hpp:174
magic_enum::bitwise_operators
Definition: magic_enum.hpp:1464
boo1::lt3::s3
@ s3
boo2::boo3::foo1::lt5::s5
@ s5
magic_enum::case_insensitive
constexpr auto case_insensitive
Definition: magic_enum.hpp:1339
loooooooooooooooooooong2
@ loooooooooooooooooooong2
Definition: test.cpp:453
boo2::boo3::foo2::loooooooooooooooooooong6
@ loooooooooooooooooooong6
Definition: test.cpp:492
lt3
lt3
Definition: test.cpp:454
Binary::TWO
@ TWO
Numbers::many
@ many
boo1::foo2::loooooooooooooooooooong6
@ loooooooooooooooooooong6
Definition: test.cpp:476
foo2::loooooooooooooooooooong6
@ loooooooooooooooooooong6
Definition: test.cpp:462
boo1::foo2::s6
@ s6
Definition: test.cpp:476
crc_hack::b5a7b602ab754d7ab30fb42c4fb28d82
@ b5a7b602ab754d7ab30fb42c4fb28d82
MAGIC_ENUM_RANGE_MAX
#define MAGIC_ENUM_RANGE_MAX
Definition: test.cpp:28
BoolTest::Yay
@ Yay
foo2::lt6
lt6
Definition: test.cpp:462
MAGIC_ENUM_RANGE_MIN
#define MAGIC_ENUM_RANGE_MIN
Definition: test.cpp:27
crc_hack_2
crc_hack_2
Definition: test.cpp:76
s1
@ s1
Definition: test.cpp:452
magic_enum.hpp
LargeNumbers::First
@ First
Binary::ONE
@ ONE
boo2::boo3::lt4
lt4
Definition: test.cpp:485
boo2::boo3::foo1::lt5
lt5
Definition: test.cpp:488
foo1
Definition: test.cpp:456
Left
@ Left
Definition: test.cpp:52
magic_enum_utility.hpp
MaxUsedAsInvalid
MaxUsedAsInvalid
Definition: test.cpp:81
boo2::boo3::lt1
lt1
Definition: test.cpp:482
lt1
lt1
Definition: test.cpp:452
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::detail::value
constexpr E value(std::size_t i) noexcept
Definition: magic_enum.hpp:679
loooooooooooooooooooong1
@ loooooooooooooooooooong1
Definition: test.cpp:452
lt4
lt4
Definition: test.cpp:455
three
@ three
Definition: test.cpp:57
Right
@ Right
Definition: test.cpp:52
crc_hack_2::b5a7b602ab754d7ab30fb42c4fb28d82
@ b5a7b602ab754d7ab30fb42c4fb28d82
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
boo1::lt3::loooooooooooooooooooong3
@ loooooooooooooooooooong3
Numbers::two
@ two
LargeNumbers
LargeNumbers
Definition: test.cpp:512
boo1::foo1
Definition: test.cpp:470
boo1::lt1
lt1
Definition: test.cpp:466
boo1::lt4::loooooooooooooooooooong4
@ loooooooooooooooooooong4
foo1::lt5
lt5
Definition: test.cpp:458
magic_enum::detail::is_reflected_v
constexpr bool is_reflected_v
Definition: magic_enum.hpp:892
magic_enum::enum_fuse
constexpr auto enum_fuse(Es... values) noexcept
Definition: magic_enum_fuse.hpp:75
DoWork
constexpr std::string_view DoWork()
Definition: test.cpp:1065
lt2
lt2
Definition: test.cpp:453
MaxUsedAsInvalid::ONE
@ ONE
magic_enum::enum_contains
constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum.hpp:1396
boo2::boo3::foo1::lt5::loooooooooooooooooooong5
@ loooooooooooooooooooong5
Numbers
Numbers
Definition: example_custom_name.cpp:44
crc_hack_2::d19f2e9e82d14b96be4fa12b8a27ee9f
@ d19f2e9e82d14b96be4fa12b8a27ee9f
boo2::boo3::lt3::loooooooooooooooooooong3
@ loooooooooooooooooooong3
REQUIRE
#define REQUIRE(...)
Definition: catch.hpp:17637
SECTION
#define SECTION(...)
Definition: catch.hpp:17677
lt3::loooooooooooooooooooong3
@ loooooooooooooooooooong3
foo1::lt5::loooooooooooooooooooong5
@ loooooooooooooooooooong5
two
@ two
Definition: test.cpp:56
magic_enum::underlying_type_t
typename underlying_type< T >::type underlying_type_t
Definition: magic_enum.hpp:1168
TEST_CASE
TEST_CASE("enum_cast")
Definition: test.cpp:108
magic_enum::is_magic_enum_supported
constexpr bool is_magic_enum_supported
Definition: magic_enum.hpp:1141
boo2::boo3::foo2
Definition: test.cpp:490
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::detail::cmp_less
constexpr bool cmp_less(L lhs, R rhs) noexcept
Definition: magic_enum.hpp:375
boo1::foo2::lt6
lt6
Definition: test.cpp:476
magic_enum_fuse.hpp
boo2::boo3::lt3::s3
@ s3
boo1::foo1::lt5::loooooooooooooooooooong5
@ loooooooooooooooooooong5
boo1::lt4
lt4
Definition: test.cpp:469
boo1::foo2
Definition: test.cpp:474
lt4::loooooooooooooooooooong4
@ loooooooooooooooooooong4
magic_enum::detail::max_v
constexpr auto max_v
Definition: magic_enum.hpp:839
magic_enum::detail::min_v
constexpr auto min_v
Definition: magic_enum.hpp:836
boo1::foo1::lt5
lt5
Definition: test.cpp:472
magic_enum::istream_operators
Definition: magic_enum_iostream.hpp:78
lt3::s3
@ s3
Color::RED
@ RED
magic_enum::customize::enum_range
Definition: magic_enum.hpp:172
boo2::boo3::lt4::loooooooooooooooooooong4
@ loooooooooooooooooooong4
catch.hpp
magic_enum::customize::enum_range::min
static constexpr int min
Definition: magic_enum.hpp:173
BoolTest::Nay
@ Nay
magic_enum::customize::customize_t
Definition: magic_enum.hpp:189
magic_enum::enum_name
constexpr auto enum_name() noexcept -> detail::enable_if_t< decltype(V), string_view >
Definition: magic_enum.hpp:1290
boo2::boo3::lt3
lt3
Definition: test.cpp:484
boo2::boo3::foo1
Definition: test.cpp:486
crc_hack
crc_hack
Definition: test.cpp:72
boo2::boo3::lt4::s4
@ s4
foo2::s6
@ s6
Definition: test.cpp:462
Directions
Directions
Definition: test.cpp:52
LargeNumbers::Second
@ Second
boo1
Definition: test.cpp:465
MaxUsedAsInvalid::TWO
@ TWO
magic_enum::detail::reflected_max
constexpr int reflected_max() noexcept
Definition: magic_enum.hpp:700
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
magic_enum::customize::default_tag
constexpr auto default_tag
Definition: magic_enum.hpp:199
boo2::boo3::foo2::s6
@ s6
Definition: test.cpp:492
boo2::boo3::foo2::lt6
lt6
Definition: test.cpp:492
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
boo1::foo1::lt5::s5
@ s5
Color::BLUE
@ BLUE
magic_enum
Definition: magic_enum.hpp:126
boo1::lt3
lt3
Definition: test.cpp:468
Binary
Binary
Definition: test.cpp:92
Down
@ Down
Definition: test.cpp:52
magic_enum_format.hpp
magic_enum::detail::reflected_min
constexpr int reflected_min() noexcept
Definition: magic_enum.hpp:684
boo1::lt4::s4
@ s4
Numbers::three
@ three
BoolTest
BoolTest
Definition: test.cpp:102
magic_enum::enum_constant
detail::enum_constant< V > enum_constant
Definition: magic_enum.hpp:1171
magic_enum::enum_type_name
constexpr auto enum_type_name() noexcept -> detail::enable_if_t< E, string_view >
Definition: magic_enum.hpp:1175
MaxUsedAsInvalid::INVALID
@ INVALID
foo1::lt5::s5
@ s5
one
@ one
Definition: test.cpp:55
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
GENERATE
#define GENERATE(...)
Definition: catch.hpp:4098
boo2
Definition: test.cpp:480
Up
@ Up
Definition: test.cpp:52
foo2
Definition: test.cpp:460
four
@ four
Definition: test.cpp:58


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