mirror of
https://github.com/Neargye/magic_enum.git
synced 2026-01-08 23:24:20 +00:00
445 lines
17 KiB
C++
445 lines
17 KiB
C++
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
|
// SPDX-License-Identifier: MIT
|
|
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
#define CATCH_CONFIG_MAIN
|
|
#include <catch2/catch.hpp>
|
|
|
|
#undef MAGIC_ENUM_RANGE_MIN
|
|
#define MAGIC_ENUM_RANGE_MIN -120
|
|
#undef MAGIC_ENUM_RANGE_MAX
|
|
#define MAGIC_ENUM_RANGE_MAX 120
|
|
#include <magic_enum/magic_enum.hpp>
|
|
#include <magic_enum/magic_enum_fuse.hpp>
|
|
#include <magic_enum/magic_enum_iostream.hpp>
|
|
|
|
#include <array>
|
|
#include <cctype>
|
|
#include <string_view>
|
|
#include <sstream>
|
|
|
|
enum class Language : int { 日本語 = 10, 한국어 = 20, English = 30, 😃 = 40, TVÅ = 50 };
|
|
|
|
enum class LanguageFlag : int {
|
|
日本語 = 1 << 1,
|
|
한국어 = 1 << 2,
|
|
English = 1 << 3,
|
|
😃 = 1 << 4
|
|
};
|
|
|
|
using namespace magic_enum;
|
|
|
|
static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
|
|
|
|
TEST_CASE("enum_cast") {
|
|
SECTION("string") {
|
|
constexpr auto lang = enum_cast<Language>("日本語");
|
|
REQUIRE(enum_cast<Language&>("한국어").value() == Language::한국어);
|
|
REQUIRE(enum_cast<const Language>("English").value() == Language::English);
|
|
REQUIRE(lang.value() == Language::日本語);
|
|
REQUIRE(enum_cast<Language>("😃").value() == Language::😃);
|
|
REQUIRE(enum_cast<Language>("TVÅ").value() == Language::TVÅ);
|
|
REQUIRE_FALSE(enum_cast<Language>("Französisch").has_value());
|
|
}
|
|
|
|
SECTION("integer") {
|
|
constexpr auto lang = enum_cast<Language>(10);
|
|
REQUIRE(enum_cast<Language&>(20).value() == Language::한국어);
|
|
REQUIRE(enum_cast<const Language>(30).value() == Language::English);
|
|
REQUIRE(lang.value() == Language::日本語);
|
|
REQUIRE(enum_cast<Language>(40).value() == Language::😃);
|
|
REQUIRE_FALSE(enum_cast<Language>(0).has_value());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("enum_integer") {
|
|
constexpr auto lang = enum_integer(Language::日本語);
|
|
Language korean = Language::한국어;
|
|
REQUIRE(enum_integer<Language&>(korean) == 20);
|
|
REQUIRE(enum_integer<const Language>(Language::English) == 30);
|
|
REQUIRE(enum_integer(Language::😃) == 40);
|
|
REQUIRE(lang == 10);
|
|
REQUIRE(enum_integer(static_cast<Language>(0)) == 0);
|
|
}
|
|
|
|
TEST_CASE("enum_index") {
|
|
constexpr auto lang = enum_index<Language>(Language::日本語);
|
|
Language korean = Language::한국어;
|
|
REQUIRE(enum_index<Language&>(korean) == 1);
|
|
REQUIRE(enum_index<const Language>(Language::English).value() == 2);
|
|
REQUIRE(enum_index(Language::😃) == 3);
|
|
REQUIRE(lang.value() == 0);
|
|
REQUIRE_FALSE(enum_index(static_cast<Language>(0)).has_value());
|
|
}
|
|
|
|
TEST_CASE("enum_contains") {
|
|
SECTION("value") {
|
|
constexpr auto lang = enum_contains(Language::日本語);
|
|
Language korean = Language::한국어;
|
|
REQUIRE(enum_contains<Language&>(korean));
|
|
REQUIRE(enum_contains<const Language>(Language::English));
|
|
REQUIRE(enum_contains(Language::😃));
|
|
REQUIRE(lang);
|
|
}
|
|
|
|
SECTION("integer") {
|
|
constexpr auto lang = enum_integer(Language::日本語);
|
|
REQUIRE(enum_contains<Language&>(lang));
|
|
REQUIRE(enum_contains<const Language>(Language::한국어));
|
|
REQUIRE(enum_contains<Language>(Language::😃));
|
|
REQUIRE_FALSE(enum_contains<Language>(static_cast<Language>(0)));
|
|
}
|
|
|
|
SECTION("string") {
|
|
auto lang = std::string{"日本語"};
|
|
REQUIRE(enum_contains<Language&>("한국어"));
|
|
REQUIRE(enum_contains<Language>("English"));
|
|
REQUIRE(enum_contains<const Language>(lang));
|
|
REQUIRE(enum_contains<Language>("😃"));
|
|
REQUIRE_FALSE(enum_contains<Language>("None"));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("enum_value") {
|
|
constexpr auto lang = enum_value<Language>(3);
|
|
REQUIRE(enum_value<Language&>(0) == Language::日本語);
|
|
REQUIRE(enum_value<const Language>(1) == Language::한국어);
|
|
REQUIRE(enum_value<Language>(2) == Language::English);
|
|
REQUIRE(lang == Language::😃);
|
|
}
|
|
|
|
TEST_CASE("enum_values") {
|
|
constexpr auto& s7 = enum_values<const Language>();
|
|
REQUIRE(s7 == std::array<Language, 5>{{Language::日本語, Language::한국어, Language::English, Language::😃, Language::TVÅ}});
|
|
}
|
|
|
|
TEST_CASE("enum_count") {
|
|
constexpr auto s7 = enum_count<Language>();
|
|
REQUIRE(s7 == 5);
|
|
}
|
|
|
|
TEST_CASE("enum_name") {
|
|
SECTION("automatic storage") {
|
|
constexpr Language lang = Language::日本語;
|
|
constexpr auto lang_name = enum_name(lang);
|
|
Language lk = Language::한국어;
|
|
REQUIRE(enum_name<Language&>(lk) == "한국어");
|
|
REQUIRE(enum_name<const Language>(Language::English) == "English");
|
|
REQUIRE(lang_name == "日本語");
|
|
REQUIRE(enum_name(Language::😃) == "😃");
|
|
REQUIRE(enum_name(Language::TVÅ) == "TVÅ");
|
|
REQUIRE(enum_name(static_cast<Language>(0)).empty());
|
|
}
|
|
|
|
SECTION("static storage") {
|
|
constexpr Language lang = Language::日本語;
|
|
constexpr auto lang_name = enum_name<lang>();
|
|
REQUIRE(enum_name<Language::한국어>() == "한국어");
|
|
REQUIRE(enum_name<Language::English>() == "English");
|
|
REQUIRE(lang_name == "日本語");
|
|
REQUIRE(enum_name<Language::😃>() == "😃");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("enum_names") {
|
|
constexpr auto& s5 = enum_names<const Language>();
|
|
REQUIRE(s5 == std::array<std::string_view, 5>{{"日本語", "한국어", "English", "😃", "TVÅ"}});
|
|
}
|
|
|
|
TEST_CASE("enum_entries") {
|
|
constexpr auto& s5 = enum_entries<const Language>();
|
|
REQUIRE(s5 == std::array<std::pair<Language, std::string_view>, 5>{{{Language::日本語, "日本語"}, {Language::한국어, "한국어"}, {Language::English, "English"}, {Language::😃, "😃"}, {Language::TVÅ, "TVÅ"}}});
|
|
}
|
|
|
|
TEST_CASE("ostream_operators") {
|
|
auto test_ostream = [](auto e, std::string name) {
|
|
using namespace magic_enum::ostream_operators;
|
|
std::stringstream ss;
|
|
ss << e;
|
|
REQUIRE(ss);
|
|
REQUIRE(ss.str() == name);
|
|
};
|
|
|
|
test_ostream(std::make_optional(Language::日本語), "日本語");
|
|
test_ostream(Language::한국어, "한국어");
|
|
test_ostream(Language::English, "English");
|
|
test_ostream(Language::😃, "😃");
|
|
test_ostream(static_cast<Language>(0), "0");
|
|
test_ostream(std::make_optional(static_cast<Language>(0)), "0");
|
|
}
|
|
|
|
TEST_CASE("istream_operators") {
|
|
auto test_istream = [](const auto e, std::string name) {
|
|
using namespace magic_enum::istream_operators;
|
|
std::istringstream ss(name);
|
|
std::decay_t<decltype(e)> v;
|
|
ss >> v;
|
|
REQUIRE(ss);
|
|
REQUIRE(v == e);
|
|
};
|
|
|
|
test_istream(Language::한국어, "한국어");
|
|
test_istream(Language::English, "English");
|
|
test_istream(Language::😃, "😃");
|
|
}
|
|
|
|
TEST_CASE("bitwise_operators") {
|
|
using namespace magic_enum::bitwise_operators;
|
|
|
|
SECTION("operator^") {
|
|
REQUIRE(enum_integer(~Language::日本語) == ~enum_integer(Language::日本語));
|
|
}
|
|
|
|
SECTION("operator|") {
|
|
REQUIRE(enum_integer(Language::日本語 | Language::한국어) == (enum_integer(Language::日本語) | enum_integer(Language::한국어)));
|
|
}
|
|
|
|
SECTION("operator&") {
|
|
REQUIRE(enum_integer(Language::日本語 & Language::한국어) == (enum_integer(Language::日本語) & enum_integer(Language::한국어)));
|
|
|
|
}
|
|
|
|
SECTION("operator^") {
|
|
REQUIRE(enum_integer(Language::日本語 ^ Language::한국어) == (enum_integer(Language::日本語) ^ enum_integer(Language::한국어)));
|
|
}
|
|
|
|
SECTION("operator|=") {
|
|
Language x5 = Language::日本語;
|
|
x5 |= Language::한국어;
|
|
REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) | enum_integer(Language::한국어)));
|
|
}
|
|
|
|
SECTION("operator&=") {
|
|
Language x5 = Language::日本語;
|
|
x5 &= Language::한국어;
|
|
REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) & enum_integer(Language::한국어)));
|
|
}
|
|
|
|
SECTION("operator^=") {
|
|
Language x5 = Language::日本語;
|
|
x5 ^= Language::한국어;
|
|
REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) ^ enum_integer(Language::한국어)));
|
|
}
|
|
}
|
|
TEST_CASE("type_traits") {
|
|
REQUIRE_FALSE(is_unscoped_enum_v<Language>);
|
|
}
|
|
|
|
TEST_CASE("enum_type_name") {
|
|
REQUIRE(enum_type_name<const Language&>() == "Language");
|
|
}
|
|
|
|
TEST_CASE("extrema") {
|
|
SECTION("min") {
|
|
REQUIRE(magic_enum::customize::enum_range<Language>::min == MAGIC_ENUM_RANGE_MIN);
|
|
REQUIRE(magic_enum::detail::reflected_min<Language, as_common<>>() == MAGIC_ENUM_RANGE_MIN);
|
|
REQUIRE(magic_enum::detail::min_v<Language, as_common<>> == 10);
|
|
}
|
|
|
|
SECTION("max") {
|
|
REQUIRE(magic_enum::customize::enum_range<Language>::max == MAGIC_ENUM_RANGE_MAX);
|
|
REQUIRE(magic_enum::detail::reflected_max<Language, as_common<>>() == MAGIC_ENUM_RANGE_MAX);
|
|
REQUIRE(magic_enum::detail::max_v<Language, as_common<>> == 50);
|
|
}
|
|
}
|
|
|
|
/* LanguageFlag tests */
|
|
TEST_CASE("flag enum_cast") {
|
|
SECTION("string") {
|
|
constexpr auto lang = enum_cast<LanguageFlag>("日本語");
|
|
REQUIRE(enum_cast<LanguageFlag&>("한국어").value() == LanguageFlag::한국어);
|
|
REQUIRE(enum_cast<const LanguageFlag>("English").value() == LanguageFlag::English);
|
|
REQUIRE(lang.value() == LanguageFlag::日本語);
|
|
REQUIRE(enum_cast<LanguageFlag>("😃").value() == LanguageFlag::😃);
|
|
REQUIRE_FALSE(enum_cast<LanguageFlag>("None").has_value());
|
|
}
|
|
|
|
SECTION("integer") {
|
|
constexpr auto lang = enum_cast<LanguageFlag>(1 << 1);
|
|
REQUIRE(enum_cast<LanguageFlag&>(1 << 2).value() == LanguageFlag::한국어);
|
|
REQUIRE(enum_cast<const LanguageFlag>(1 << 3).value() == LanguageFlag::English);
|
|
REQUIRE(lang.value() == LanguageFlag::日本語);
|
|
REQUIRE(enum_cast<LanguageFlag>(1 << 4).value() == LanguageFlag::😃);
|
|
REQUIRE_FALSE(enum_cast<LanguageFlag>(0).has_value());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("flag enum_index") {
|
|
constexpr auto lang = enum_index<LanguageFlag>(LanguageFlag::日本語);
|
|
LanguageFlag korean = LanguageFlag::한국어;
|
|
REQUIRE(enum_index<LanguageFlag&>(korean).value() == 1);
|
|
REQUIRE(enum_index<const LanguageFlag>(LanguageFlag::English).value() == 2);
|
|
REQUIRE(enum_index(LanguageFlag::😃).value() == 3);
|
|
REQUIRE(lang.value() == 0);
|
|
REQUIRE_FALSE(enum_index(static_cast<LanguageFlag>(0)).has_value());
|
|
}
|
|
|
|
TEST_CASE("flag enum_contains") {
|
|
SECTION("value") {
|
|
constexpr auto lang = enum_index<LanguageFlag>(LanguageFlag::日本語);
|
|
LanguageFlag korean = LanguageFlag::한국어;
|
|
REQUIRE(enum_contains<LanguageFlag&>(korean));
|
|
REQUIRE(enum_contains<const LanguageFlag>(LanguageFlag::English));
|
|
REQUIRE(enum_contains(LanguageFlag::😃));
|
|
REQUIRE(lang);
|
|
REQUIRE_FALSE(enum_contains(static_cast<LanguageFlag>(0)));
|
|
}
|
|
|
|
SECTION("integer") {
|
|
constexpr auto lang = enum_contains<LanguageFlag&>(1 << 1);
|
|
REQUIRE(lang);
|
|
REQUIRE(enum_contains<const LanguageFlag>(1 << 2));
|
|
REQUIRE(enum_contains<LanguageFlag>(1 << 3));
|
|
REQUIRE(enum_contains<LanguageFlag>(1 << 4));
|
|
REQUIRE_FALSE(enum_contains(static_cast<LanguageFlag>(0)));
|
|
}
|
|
|
|
SECTION("string") {
|
|
auto lang = std::string{"日本語"};
|
|
REQUIRE(enum_contains<LanguageFlag&>("한국어"));
|
|
REQUIRE(enum_contains<LanguageFlag>("English"));
|
|
REQUIRE(enum_contains<const LanguageFlag>(lang));
|
|
REQUIRE(enum_contains<LanguageFlag>("😃"));
|
|
REQUIRE_FALSE(enum_contains<LanguageFlag>("None"));
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE("flag enum_value") {
|
|
constexpr auto lang = enum_value<LanguageFlag>(3);
|
|
REQUIRE(enum_value<LanguageFlag&>(0) == LanguageFlag::日本語);
|
|
REQUIRE(enum_value<const LanguageFlag>(1) == LanguageFlag::한국어);
|
|
REQUIRE(enum_value<LanguageFlag>(2) == LanguageFlag::English);
|
|
REQUIRE(lang == LanguageFlag::😃);
|
|
}
|
|
|
|
TEST_CASE("flag enum_values") {
|
|
constexpr auto& s5 = enum_values<const LanguageFlag>();
|
|
REQUIRE(s5 == std::array<LanguageFlag, 4>{{LanguageFlag::日本語, LanguageFlag::한국어, LanguageFlag::English, LanguageFlag::😃}});
|
|
}
|
|
|
|
TEST_CASE("flag enum_count") {
|
|
constexpr auto s5 = enum_count<LanguageFlag>();
|
|
REQUIRE(s5 == 4);
|
|
}
|
|
|
|
TEST_CASE("flag enum_name") {
|
|
SECTION("automatic storage") {
|
|
constexpr LanguageFlag lang = LanguageFlag::日本語;
|
|
constexpr auto lang_name = enum_name(lang);
|
|
LanguageFlag lk = LanguageFlag::한국어;
|
|
REQUIRE(enum_name<LanguageFlag&>(lk) == "한국어");
|
|
REQUIRE(enum_name<const LanguageFlag>(LanguageFlag::English) == "English");
|
|
REQUIRE(lang_name == "日本語");
|
|
REQUIRE(enum_name(LanguageFlag::😃) == "😃");
|
|
REQUIRE(enum_name(static_cast<LanguageFlag>(0)).empty());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("flag enum_flags_name") {
|
|
constexpr LanguageFlag lang = LanguageFlag::日本語;
|
|
auto lang_name = enum_flags_name(lang);
|
|
LanguageFlag lk = LanguageFlag::한국어;
|
|
REQUIRE(enum_flags_name<LanguageFlag&>(lk) == "한국어");
|
|
REQUIRE(enum_flags_name<const LanguageFlag>(LanguageFlag::English) == "English");
|
|
REQUIRE(lang_name == "日本語");
|
|
REQUIRE(enum_flags_name(LanguageFlag::😃) == "😃");
|
|
REQUIRE(enum_flags_name(static_cast<LanguageFlag>(0)).empty());
|
|
}
|
|
|
|
TEST_CASE("flag enum_names") {
|
|
constexpr auto& s5 = enum_names<const LanguageFlag>();
|
|
REQUIRE(s5 == std::array<std::string_view, 4>{{"日本語", "한국어", "English", "😃"}});
|
|
}
|
|
|
|
TEST_CASE("flag enum_entries") {
|
|
constexpr auto& s5 = enum_entries<const LanguageFlag>();
|
|
REQUIRE(s5 == std::array<std::pair<LanguageFlag, std::string_view>, 4>{{{LanguageFlag::日本語, "日本語"}, {LanguageFlag::한국어, "한국어"}, {LanguageFlag::English, "English"}, {LanguageFlag::😃, "😃"}}});
|
|
}
|
|
|
|
TEST_CASE("flag ostream_operators") {
|
|
auto test_ostream = [](auto e, std::string name) {
|
|
using namespace magic_enum::ostream_operators;
|
|
std::stringstream ss;
|
|
ss << e;
|
|
REQUIRE(ss.str() == name);
|
|
};
|
|
|
|
test_ostream(std::make_optional(LanguageFlag::日本語), "日本語");
|
|
test_ostream(LanguageFlag::한국어, "한국어");
|
|
test_ostream(LanguageFlag::English, "English");
|
|
test_ostream(LanguageFlag::😃, "😃");
|
|
test_ostream(static_cast<LanguageFlag>(0), "0");
|
|
test_ostream(std::make_optional(static_cast<LanguageFlag>(0)), "0");
|
|
}
|
|
|
|
TEST_CASE("flag istream_operators") {
|
|
auto test_istream = [](const auto e, std::string name) {
|
|
using namespace magic_enum::istream_operators;
|
|
std::istringstream ss(name);
|
|
std::decay_t<decltype(e)> v;
|
|
ss >> v;
|
|
REQUIRE(v == e);
|
|
REQUIRE(ss);
|
|
};
|
|
|
|
test_istream(LanguageFlag::한국어, "한국어");
|
|
test_istream(LanguageFlag::English, "English");
|
|
test_istream(LanguageFlag::😃, "😃");
|
|
}
|
|
|
|
|
|
TEST_CASE("flag bitwise_operators") {
|
|
using namespace magic_enum::bitwise_operators;
|
|
SECTION("operator~") {
|
|
REQUIRE(enum_integer(~LanguageFlag::日本語) == ~enum_integer(LanguageFlag::日本語));
|
|
}
|
|
|
|
SECTION("operator|") {
|
|
REQUIRE(enum_integer(LanguageFlag::日本語 | LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) | enum_integer(LanguageFlag::한국어)));
|
|
}
|
|
|
|
SECTION("operator&") {
|
|
REQUIRE(enum_integer(LanguageFlag::日本語 & LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) & enum_integer(LanguageFlag::한국어)));
|
|
}
|
|
|
|
SECTION("operator^") {
|
|
REQUIRE(enum_integer(LanguageFlag::日本語 ^ LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) ^ enum_integer(LanguageFlag::한국어)));
|
|
}
|
|
|
|
SECTION("operator|=") {
|
|
LanguageFlag x5 = LanguageFlag::日本語;
|
|
x5 |= LanguageFlag::한국어;
|
|
REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) | enum_integer(LanguageFlag::한국어)));
|
|
}
|
|
|
|
SECTION("operator&=") {
|
|
LanguageFlag x5 = LanguageFlag::日本語;
|
|
x5 &= LanguageFlag::한국어;
|
|
REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) & enum_integer(LanguageFlag::한국어)));
|
|
}
|
|
|
|
SECTION("operator^=") {
|
|
LanguageFlag x5 = LanguageFlag::日本語;
|
|
x5 ^= LanguageFlag::한국어;
|
|
REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) ^ enum_integer(LanguageFlag::한국어)));
|
|
}
|
|
}
|