From 0a2de2f496e827926e4c3ade7da6c47f8faac9ad Mon Sep 17 00:00:00 2001 From: Ghabry Date: Wed, 22 Nov 2023 16:14:30 +0100 Subject: [PATCH] EnumTags: Support non-monotonic enums (e.g. EventCommands) Add Unit Test --- CMakeLists.txt | 1 + Makefile.am | 2 + generator/templates/rpg_header.tmpl | 10 + src/generated/lcf/rpg/battleranimation.h | 5 + src/generated/lcf/rpg/commonevent.h | 5 + src/generated/lcf/rpg/eventcommand.h | 156 ++++++ src/generated/lcf/rpg/eventpage.h | 21 + src/lcf/enum_tags.h | 141 +++++- tests/enum_tags.cpp | 579 +++++++++++++++++++++++ 9 files changed, 897 insertions(+), 23 deletions(-) create mode 100644 tests/enum_tags.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index de8dec18..9988fc9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -462,6 +462,7 @@ endif() if(LIBLCF_ENABLE_TESTS) file(GLOB TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/*.cpp) add_executable(test_runner_lcf EXCLUDE_FROM_ALL ${TEST_FILES}) + target_compile_definitions(test_runner_lcf PRIVATE DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING=1) set_target_properties(test_runner_lcf PROPERTIES OUTPUT_NAME "test_runner") target_link_libraries(test_runner_lcf lcf) add_custom_target(check_lcf COMMAND test_runner_lcf) diff --git a/Makefile.am b/Makefile.am index 85033b16..d378e2be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -332,6 +332,7 @@ test_runner_SOURCES = \ tests/dbbitarray.cpp \ tests/dbstring.cpp \ tests/doctest.h \ + tests/enum_tags.cpp \ tests/flag_set.cpp \ tests/test_main.cpp \ tests/time_stamp.cpp \ @@ -342,6 +343,7 @@ test_runner_CPPFLAGS = \ -I$(srcdir)/src/generated test_runner_CXXFLAGS = \ -std=gnu++17 \ + -DDOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING=1 \ $(EXPAT_CXXFLAGS) \ $(ICU_CXXFLAGS) test_runner_LDADD = \ diff --git a/generator/templates/rpg_header.tmpl b/generator/templates/rpg_header.tmpl index 858ff32a..ea8d899d 100644 --- a/generator/templates/rpg_header.tmpl +++ b/generator/templates/rpg_header.tmpl @@ -52,6 +52,16 @@ namespace rpg { "{{ field.0 }}"{%- if not loop.last %},{% endif %} {%- endfor %} ); + {%- else %} + static constexpr auto k{{ name }}Tags = lcf::EnumTags{ + {%- for field in enum %} + {%- if name != "Code" %} + {{ name }}_{{ field.0 }}, "{{ field.0 }}"{%- if not loop.last %},{% endif %} + {%- else %} + {{ name }}::{{ field.0 }}, "{{ field.0 }}"{%- if not loop.last %},{% endif %} + {%- endif %} + {%- endfor %} + }; {%- endif %} {%- endfor %} {% endif %} diff --git a/src/generated/lcf/rpg/battleranimation.h b/src/generated/lcf/rpg/battleranimation.h index 091adaea..9394428c 100644 --- a/src/generated/lcf/rpg/battleranimation.h +++ b/src/generated/lcf/rpg/battleranimation.h @@ -34,6 +34,11 @@ namespace rpg { Speed_medium = 14, Speed_fast = 8 }; + static constexpr auto kSpeedTags = lcf::EnumTags{ + Speed_slow, "slow", + Speed_medium, "medium", + Speed_fast, "fast" + }; enum Pose { Pose_Idle = 0, Pose_AttackRight = 1, diff --git a/src/generated/lcf/rpg/commonevent.h b/src/generated/lcf/rpg/commonevent.h index b47afbfb..55eb655a 100644 --- a/src/generated/lcf/rpg/commonevent.h +++ b/src/generated/lcf/rpg/commonevent.h @@ -34,6 +34,11 @@ namespace rpg { Trigger_parallel = 4, Trigger_call = 5 }; + static constexpr auto kTriggerTags = lcf::EnumTags{ + Trigger_automatic, "automatic", + Trigger_parallel, "parallel", + Trigger_call, "call" + }; int ID = 0; DBString name; diff --git a/src/generated/lcf/rpg/eventcommand.h b/src/generated/lcf/rpg/eventcommand.h index a8e59e3b..f54c9f05 100644 --- a/src/generated/lcf/rpg/eventcommand.h +++ b/src/generated/lcf/rpg/eventcommand.h @@ -184,6 +184,162 @@ namespace rpg { Maniac_EditTile = 3028, Maniac_ControlTextProcessing = 3029 }; + static constexpr auto kCodeTags = lcf::EnumTags{ + Code::END, "END", + Code::CallCommonEvent, "CallCommonEvent", + Code::ForceFlee, "ForceFlee", + Code::EnableCombo, "EnableCombo", + Code::ChangeClass, "ChangeClass", + Code::ChangeBattleCommands, "ChangeBattleCommands", + Code::OpenLoadMenu, "OpenLoadMenu", + Code::ExitGame, "ExitGame", + Code::ToggleAtbMode, "ToggleAtbMode", + Code::ToggleFullscreen, "ToggleFullscreen", + Code::OpenVideoOptions, "OpenVideoOptions", + Code::ShowMessage, "ShowMessage", + Code::MessageOptions, "MessageOptions", + Code::ChangeFaceGraphic, "ChangeFaceGraphic", + Code::ShowChoice, "ShowChoice", + Code::InputNumber, "InputNumber", + Code::ControlSwitches, "ControlSwitches", + Code::ControlVars, "ControlVars", + Code::TimerOperation, "TimerOperation", + Code::ChangeGold, "ChangeGold", + Code::ChangeItems, "ChangeItems", + Code::ChangePartyMembers, "ChangePartyMembers", + Code::ChangeExp, "ChangeExp", + Code::ChangeLevel, "ChangeLevel", + Code::ChangeParameters, "ChangeParameters", + Code::ChangeSkills, "ChangeSkills", + Code::ChangeEquipment, "ChangeEquipment", + Code::ChangeHP, "ChangeHP", + Code::ChangeSP, "ChangeSP", + Code::ChangeCondition, "ChangeCondition", + Code::FullHeal, "FullHeal", + Code::SimulatedAttack, "SimulatedAttack", + Code::ChangeHeroName, "ChangeHeroName", + Code::ChangeHeroTitle, "ChangeHeroTitle", + Code::ChangeSpriteAssociation, "ChangeSpriteAssociation", + Code::ChangeActorFace, "ChangeActorFace", + Code::ChangeVehicleGraphic, "ChangeVehicleGraphic", + Code::ChangeSystemBGM, "ChangeSystemBGM", + Code::ChangeSystemSFX, "ChangeSystemSFX", + Code::ChangeSystemGraphics, "ChangeSystemGraphics", + Code::ChangeScreenTransitions, "ChangeScreenTransitions", + Code::EnemyEncounter, "EnemyEncounter", + Code::OpenShop, "OpenShop", + Code::ShowInn, "ShowInn", + Code::EnterHeroName, "EnterHeroName", + Code::Teleport, "Teleport", + Code::MemorizeLocation, "MemorizeLocation", + Code::RecallToLocation, "RecallToLocation", + Code::EnterExitVehicle, "EnterExitVehicle", + Code::SetVehicleLocation, "SetVehicleLocation", + Code::ChangeEventLocation, "ChangeEventLocation", + Code::TradeEventLocations, "TradeEventLocations", + Code::StoreTerrainID, "StoreTerrainID", + Code::StoreEventID, "StoreEventID", + Code::EraseScreen, "EraseScreen", + Code::ShowScreen, "ShowScreen", + Code::TintScreen, "TintScreen", + Code::FlashScreen, "FlashScreen", + Code::ShakeScreen, "ShakeScreen", + Code::PanScreen, "PanScreen", + Code::WeatherEffects, "WeatherEffects", + Code::ShowPicture, "ShowPicture", + Code::MovePicture, "MovePicture", + Code::ErasePicture, "ErasePicture", + Code::ShowBattleAnimation, "ShowBattleAnimation", + Code::PlayerVisibility, "PlayerVisibility", + Code::FlashSprite, "FlashSprite", + Code::MoveEvent, "MoveEvent", + Code::ProceedWithMovement, "ProceedWithMovement", + Code::HaltAllMovement, "HaltAllMovement", + Code::Wait, "Wait", + Code::PlayBGM, "PlayBGM", + Code::FadeOutBGM, "FadeOutBGM", + Code::MemorizeBGM, "MemorizeBGM", + Code::PlayMemorizedBGM, "PlayMemorizedBGM", + Code::PlaySound, "PlaySound", + Code::PlayMovie, "PlayMovie", + Code::KeyInputProc, "KeyInputProc", + Code::ChangeMapTileset, "ChangeMapTileset", + Code::ChangePBG, "ChangePBG", + Code::ChangeEncounterSteps, "ChangeEncounterSteps", + Code::TileSubstitution, "TileSubstitution", + Code::TeleportTargets, "TeleportTargets", + Code::ChangeTeleportAccess, "ChangeTeleportAccess", + Code::EscapeTarget, "EscapeTarget", + Code::ChangeEscapeAccess, "ChangeEscapeAccess", + Code::OpenSaveMenu, "OpenSaveMenu", + Code::ChangeSaveAccess, "ChangeSaveAccess", + Code::OpenMainMenu, "OpenMainMenu", + Code::ChangeMainMenuAccess, "ChangeMainMenuAccess", + Code::ConditionalBranch, "ConditionalBranch", + Code::Label, "Label", + Code::JumpToLabel, "JumpToLabel", + Code::Loop, "Loop", + Code::BreakLoop, "BreakLoop", + Code::EndEventProcessing, "EndEventProcessing", + Code::EraseEvent, "EraseEvent", + Code::CallEvent, "CallEvent", + Code::Comment, "Comment", + Code::GameOver, "GameOver", + Code::ReturntoTitleScreen, "ReturntoTitleScreen", + Code::ChangeMonsterHP, "ChangeMonsterHP", + Code::ChangeMonsterMP, "ChangeMonsterMP", + Code::ChangeMonsterCondition, "ChangeMonsterCondition", + Code::ShowHiddenMonster, "ShowHiddenMonster", + Code::ChangeBattleBG, "ChangeBattleBG", + Code::ShowBattleAnimation_B, "ShowBattleAnimation_B", + Code::ConditionalBranch_B, "ConditionalBranch_B", + Code::TerminateBattle, "TerminateBattle", + Code::ShowMessage_2, "ShowMessage_2", + Code::ShowChoiceOption, "ShowChoiceOption", + Code::ShowChoiceEnd, "ShowChoiceEnd", + Code::VictoryHandler, "VictoryHandler", + Code::EscapeHandler, "EscapeHandler", + Code::DefeatHandler, "DefeatHandler", + Code::EndBattle, "EndBattle", + Code::Transaction, "Transaction", + Code::NoTransaction, "NoTransaction", + Code::EndShop, "EndShop", + Code::Stay, "Stay", + Code::NoStay, "NoStay", + Code::EndInn, "EndInn", + Code::ElseBranch, "ElseBranch", + Code::EndBranch, "EndBranch", + Code::EndLoop, "EndLoop", + Code::Comment_2, "Comment_2", + Code::ElseBranch_B, "ElseBranch_B", + Code::EndBranch_B, "EndBranch_B", + Code::Maniac_GetSaveInfo, "Maniac_GetSaveInfo", + Code::Maniac_Save, "Maniac_Save", + Code::Maniac_Load, "Maniac_Load", + Code::Maniac_EndLoadProcess, "Maniac_EndLoadProcess", + Code::Maniac_GetMousePosition, "Maniac_GetMousePosition", + Code::Maniac_SetMousePosition, "Maniac_SetMousePosition", + Code::Maniac_ShowStringPicture, "Maniac_ShowStringPicture", + Code::Maniac_GetPictureInfo, "Maniac_GetPictureInfo", + Code::Maniac_ControlBattle, "Maniac_ControlBattle", + Code::Maniac_ControlAtbGauge, "Maniac_ControlAtbGauge", + Code::Maniac_ChangeBattleCommandEx, "Maniac_ChangeBattleCommandEx", + Code::Maniac_GetBattleInfo, "Maniac_GetBattleInfo", + Code::Maniac_ControlVarArray, "Maniac_ControlVarArray", + Code::Maniac_KeyInputProcEx, "Maniac_KeyInputProcEx", + Code::Maniac_RewriteMap, "Maniac_RewriteMap", + Code::Maniac_ControlGlobalSave, "Maniac_ControlGlobalSave", + Code::Maniac_ChangePictureId, "Maniac_ChangePictureId", + Code::Maniac_SetGameOption, "Maniac_SetGameOption", + Code::Maniac_CallCommand, "Maniac_CallCommand", + Code::Maniac_ControlStrings, "Maniac_ControlStrings", + Code::Maniac_GetGameInfo, "Maniac_GetGameInfo", + Code::Maniac_EditPicture, "Maniac_EditPicture", + Code::Maniac_WritePicture, "Maniac_WritePicture", + Code::Maniac_AddMoveRoute, "Maniac_AddMoveRoute", + Code::Maniac_EditTile, "Maniac_EditTile", + Code::Maniac_ControlTextProcessing, "Maniac_ControlTextProcessing" + }; int32_t code = 0; int32_t indent = 0; diff --git a/src/generated/lcf/rpg/eventpage.h b/src/generated/lcf/rpg/eventpage.h index 2b79f9fe..4a47bd87 100644 --- a/src/generated/lcf/rpg/eventpage.h +++ b/src/generated/lcf/rpg/eventpage.h @@ -123,6 +123,14 @@ namespace rpg { MoveSpeed_double = 5, MoveSpeed_fourfold = 6 }; + static constexpr auto kMoveSpeedTags = lcf::EnumTags{ + MoveSpeed_eighth, "eighth", + MoveSpeed_quarter, "quarter", + MoveSpeed_half, "half", + MoveSpeed_normal, "normal", + MoveSpeed_double, "double", + MoveSpeed_fourfold, "fourfold" + }; enum ManiacEventInfo { ManiacEventInfo_action = 0, ManiacEventInfo_touched = 1, @@ -136,6 +144,19 @@ namespace rpg { ManiacEventInfo_common_event = 32, ManiacEventInfo_battle_event = 64 }; + static constexpr auto kManiacEventInfoTags = lcf::EnumTags{ + ManiacEventInfo_action, "action", + ManiacEventInfo_touched, "touched", + ManiacEventInfo_collision, "collision", + ManiacEventInfo_auto_start, "auto_start", + ManiacEventInfo_parallel, "parallel", + ManiacEventInfo_called, "called", + ManiacEventInfo_battle_start, "battle_start", + ManiacEventInfo_battle_parallel, "battle_parallel", + ManiacEventInfo_map_event, "map_event", + ManiacEventInfo_common_event, "common_event", + ManiacEventInfo_battle_event, "battle_event" + }; int ID = 0; EventPageCondition condition; diff --git a/src/lcf/enum_tags.h b/src/lcf/enum_tags.h index 2e6f9aa5..a36ac782 100644 --- a/src/lcf/enum_tags.h +++ b/src/lcf/enum_tags.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace lcf { @@ -22,24 +23,54 @@ template class EnumTags { public: static constexpr size_t num_tags = N; - using int_type = typename std::make_unsigned::type>::type; - using iterator = char const * const *; + using int_type = typename std::underlying_type::type; + + struct EnumItem { + int_type value; + const char* name; + + constexpr EnumItem() noexcept : value(), name() {} + constexpr EnumItem(int_type value, const char* name) noexcept : value(value), name(name) {} + }; + + using iterator = EnumItem const *; using reverse_iterator = std::reverse_iterator; - template - explicit constexpr EnumTags(const char (&...literals)[LN]) : _tags{{literals...}} {} + template + explicit constexpr EnumTags(Args const&...args) noexcept { + using FirstElemT = std::tuple_element_t<0, std::tuple>; + + if constexpr (std::is_array_v) { + // Passed in via makeEnumTags + AddMonotonicTag<0>(args...); + monotonic_from_zero = true; + return; + } else { + // Passed in as {A, "A", B, "B", ...} (for non-monotonic enums) + AddTag<0>(args...); + int_type i = 0; + for (const auto& it : _tags) { + if (it.value != i) { + monotonic_from_zero = false; + } + ++i; + } + } + } - constexpr const char* tag(E etag) const { return tag(int_type(etag)); } - constexpr const char* tag(int_type idx) const { return _tags[idx]; } + constexpr const char* tag(int_type value) const; + constexpr const char* tag(E etag) const; - constexpr const char* operator[](E etag) const { return tag(etag); } - constexpr const char* operator[](int_type idx) const { return tag(idx); } + constexpr const char* operator[](E etag) const; + constexpr const char* operator[](int_type value) const; + bool has_etag(const char* tag) const; bool etag(const char* tag, E& result) const; E etagOr(const char* tag, E other) const; - int_type idx(const char* tag) const; - const std::array& tags() const { return _tags; } + const std::array& tags() const { return _tags; } + + constexpr bool is_monotonic_from_zero() const { return monotonic_from_zero; } constexpr iterator begin() const { return iterator(_tags.data()); } constexpr iterator end() const { return iterator(_tags.data() + size()); } @@ -50,41 +81,105 @@ class EnumTags { reverse_iterator rbegin() const { return reverse_iterator(end()); } reverse_iterator rend() const { return reverse_iterator(begin()); } - static constexpr size_t size() { return num_tags; } + constexpr size_t size() const { return num_tags; } private: - const std::array _tags; + template + constexpr void AddTag(E value, const char* name, Next const&...next) noexcept { + _tags[I] = {int_type(value), name}; + + if constexpr (sizeof...(Next) > 0) { + AddTag(next...); + } + } + + template + constexpr void AddMonotonicTag(const char* name, Next const&...next) noexcept { + _tags[I] = {I, name}; + + if constexpr (sizeof...(Next) > 0) { + AddMonotonicTag(next...); + } + } + + std::array _tags; + bool monotonic_from_zero = true; }; +template +EnumTags(ValueType const&, const char*, Next const&...) -> EnumTags; + template constexpr EnumTags makeEnumTags(const char (&...literals)[N]) { return EnumTags(literals...); } template -inline typename EnumTags::int_type EnumTags::idx(const char* tag) const { +inline constexpr const char* EnumTags::tag(E etag) const { + return tag(int_type(etag)); +} + +template +inline constexpr const char* EnumTags::tag(int_type value) const { + if (monotonic_from_zero) { + if (value < 0 || value >= N) { + return nullptr; + } else { + return _tags[value].name; + } + } + + for (const auto& it: _tags) { + if (it.value == value) { + return it.name; + } + } + + return nullptr; +} + +template +inline constexpr const char* EnumTags::operator[](E etag) const { + return tag(etag); +} + +template +inline constexpr const char* EnumTags::operator[](int_type value) const { + return tag(value); +} + +template +inline bool EnumTags::has_etag(const char* tag) const { for (size_t i = 0; i < _tags.size(); ++i) { - if (std::strcmp(_tags[i], tag) == 0) { - return i; + if (std::strcmp(_tags[i].name, tag) == 0) { + return true; } } - return -1; + + return false; } template inline bool EnumTags::etag(const char* tag, E& result) const { - auto i = idx(tag); - if (i < 0) { - return false; + for (size_t i = 0; i < _tags.size(); ++i) { + if (std::strcmp(_tags[i].name, tag) == 0) { + result = E(_tags[i].value); + return true; + } } - result = E(i); - return true; + + return false; } template inline E EnumTags::etagOr(const char* tag, E other) const { - auto i = idx(tag); - return (i >= 0) ? E(i) : other; + for (size_t i = 0; i < _tags.size(); ++i) { + if (std::strcmp(_tags[i].name, tag) == 0) { + return E(_tags[i].value); + } + } + + return other; } } //namespace lcf diff --git a/tests/enum_tags.cpp b/tests/enum_tags.cpp new file mode 100644 index 00000000..62b99895 --- /dev/null +++ b/tests/enum_tags.cpp @@ -0,0 +1,579 @@ +/* + * This file is part of liblcf. Copyright (c) liblcf authors. + * https://github.com/EasyRPG/liblcf - https://easyrpg.org + * + * liblcf is Free/Libre Open Source Software, released under the MIT License. + * For the full copyright and license information, please view the COPYING + * file that was distributed with this source code. + */ + +#include "doctest.h" +#include "lcf/enum_tags.h" +#include + +using namespace lcf; + +enum Color { + Color_Red, + Color_Green, + Color_Blue, + Color_Yellow +}; + +static constexpr auto kColorTags = lcf::EnumTags{ + Color_Red, "Red", + Color_Green, "Green", + Color_Blue, "Blue", + Color_Yellow, "Yellow" +}; + +static constexpr auto kColorTags2 = lcf::makeEnumTags( + "Red", + "Green", + "Blue", + "Yellow" +); + +enum class Name { + Aina = 2, + Brian = 4, + Carol = -1, +}; + +static constexpr auto kNameTags = lcf::EnumTags{ + Name::Aina, "Aina", + Name::Brian, "Brian", + Name::Carol, "Carol" +}; + +TEST_SUITE_BEGIN("enum_tags"); + +TEST_CASE("size") { + REQUIRE_EQ(kColorTags.size(), 4); + REQUIRE_EQ(kNameTags.size(), 3); +} + +TEST_CASE("monotonic from zero") { + REQUIRE(kColorTags.is_monotonic_from_zero()); + REQUIRE(kColorTags2.is_monotonic_from_zero()); + REQUIRE(!kNameTags.is_monotonic_from_zero()); +} + +TEST_CASE("tag int") { + REQUIRE_EQ(kColorTags.tag(0), "Red"); + REQUIRE_EQ(kColorTags.tag(3), "Yellow"); + + REQUIRE_EQ(kColorTags.tag(4), nullptr); + + REQUIRE_EQ(kNameTags.tag(2), "Aina"); + REQUIRE_EQ(kNameTags.tag(4), "Brian"); + REQUIRE_EQ(kNameTags.tag(-1), "Carol"); + + REQUIRE_EQ(kNameTags.tag(0), nullptr); + REQUIRE_EQ(kNameTags.tag(-3), nullptr); + + REQUIRE_EQ(kColorTags[0], "Red"); + REQUIRE_EQ(kColorTags[4], nullptr); + + REQUIRE_EQ(kNameTags[2], "Aina"); + REQUIRE_EQ(kNameTags[-1], "Carol"); + REQUIRE_EQ(kNameTags[0], nullptr); +} + +TEST_CASE("tag enum") { + REQUIRE_EQ(kColorTags.tag(Color_Red), "Red"); + REQUIRE_EQ(kColorTags.tag(Color_Yellow), "Yellow"); + + REQUIRE_EQ(kNameTags.tag(Name::Aina), "Aina"); + REQUIRE_EQ(kNameTags.tag(Name::Brian), "Brian"); + + REQUIRE_EQ(kColorTags[Color_Red], "Red"); + REQUIRE_EQ(kColorTags[Color_Yellow], "Yellow"); + + REQUIRE_EQ(kNameTags[Name::Aina], "Aina"); + REQUIRE_EQ(kNameTags[Name::Brian], "Brian"); +} + +TEST_CASE("etag") { + Color result; + + REQUIRE(kColorTags.etag("Blue", result)); + REQUIRE_EQ(result, Color_Blue); + + REQUIRE(!kColorTags.etag("NotInEnum", result)); + + Name nresult; + + REQUIRE(kNameTags.etag("Carol", nresult)); + REQUIRE_EQ(nresult, Name::Carol); + + REQUIRE(!kNameTags.etag("NotInEnum", nresult)); +} + +TEST_CASE("etagOr") { + REQUIRE_EQ(kColorTags.etagOr("Blue", Color_Yellow), Color_Blue); + REQUIRE_EQ(kColorTags.etagOr("NotInEnum", Color_Yellow), Color_Yellow); +} + +TEST_CASE("has_etag") { + REQUIRE(kColorTags.has_etag("Blue")); + REQUIRE(!kColorTags.has_etag("NotInEnum")); + + REQUIRE(kNameTags.has_etag("Aina")); + REQUIRE(kNameTags.has_etag("Carol")); + REQUIRE(!kNameTags.has_etag("NotInEnum")); +} + +TEST_CASE("iterator") { + for (auto it = kNameTags.begin(); it != kNameTags.end(); ++it) { + REQUIRE(kNameTags.has_etag(it->name)); + } + + for (auto it = kNameTags.cbegin(); it != kNameTags.cend(); ++it) { + REQUIRE(kNameTags.has_etag(it->name)); + } + + for (auto it = kNameTags.rbegin(); it != kNameTags.rend(); ++it) { + REQUIRE(kNameTags.has_etag(it->name)); + } +} + +// API Test for the Key Enum in Player. Exceeds int8_t +enum Overflow : uint8_t { + Val_0, + Val_1, + Val_2, + Val_3, + Val_4, + Val_5, + Val_6, + Val_7, + Val_8, + Val_9, + Val_10, + Val_11, + Val_12, + Val_13, + Val_14, + Val_15, + Val_16, + Val_17, + Val_18, + Val_19, + Val_20, + Val_21, + Val_22, + Val_23, + Val_24, + Val_25, + Val_26, + Val_27, + Val_28, + Val_29, + Val_30, + Val_31, + Val_32, + Val_33, + Val_34, + Val_35, + Val_36, + Val_37, + Val_38, + Val_39, + Val_40, + Val_41, + Val_42, + Val_43, + Val_44, + Val_45, + Val_46, + Val_47, + Val_48, + Val_49, + Val_50, + Val_51, + Val_52, + Val_53, + Val_54, + Val_55, + Val_56, + Val_57, + Val_58, + Val_59, + Val_60, + Val_61, + Val_62, + Val_63, + Val_64, + Val_65, + Val_66, + Val_67, + Val_68, + Val_69, + Val_70, + Val_71, + Val_72, + Val_73, + Val_74, + Val_75, + Val_76, + Val_77, + Val_78, + Val_79, + Val_80, + Val_81, + Val_82, + Val_83, + Val_84, + Val_85, + Val_86, + Val_87, + Val_88, + Val_89, + Val_90, + Val_91, + Val_92, + Val_93, + Val_94, + Val_95, + Val_96, + Val_97, + Val_98, + Val_99, + Val_100, + Val_101, + Val_102, + Val_103, + Val_104, + Val_105, + Val_106, + Val_107, + Val_108, + Val_109, + Val_110, + Val_111, + Val_112, + Val_113, + Val_114, + Val_115, + Val_116, + Val_117, + Val_118, + Val_119, + Val_120, + Val_121, + Val_122, + Val_123, + Val_124, + Val_125, + Val_126, + Val_127, + Val_128, + Val_129, + Val_130 +}; + +static constexpr auto kOverflowTags = lcf::EnumTags{ + Val_0, "Val_0", + Val_1, "Val_1", + Val_2, "Val_2", + Val_3, "Val_3", + Val_4, "Val_4", + Val_5, "Val_5", + Val_6, "Val_6", + Val_7, "Val_7", + Val_8, "Val_8", + Val_9, "Val_9", + Val_10, "Val_10", + Val_11, "Val_11", + Val_12, "Val_12", + Val_13, "Val_13", + Val_14, "Val_14", + Val_15, "Val_15", + Val_16, "Val_16", + Val_17, "Val_17", + Val_18, "Val_18", + Val_19, "Val_19", + Val_20, "Val_20", + Val_21, "Val_21", + Val_22, "Val_22", + Val_23, "Val_23", + Val_24, "Val_24", + Val_25, "Val_25", + Val_26, "Val_26", + Val_27, "Val_27", + Val_28, "Val_28", + Val_29, "Val_29", + Val_30, "Val_30", + Val_31, "Val_31", + Val_32, "Val_32", + Val_33, "Val_33", + Val_34, "Val_34", + Val_35, "Val_35", + Val_36, "Val_36", + Val_37, "Val_37", + Val_38, "Val_38", + Val_39, "Val_39", + Val_40, "Val_40", + Val_41, "Val_41", + Val_42, "Val_42", + Val_43, "Val_43", + Val_44, "Val_44", + Val_45, "Val_45", + Val_46, "Val_46", + Val_47, "Val_47", + Val_48, "Val_48", + Val_49, "Val_49", + Val_50, "Val_50", + Val_51, "Val_51", + Val_52, "Val_52", + Val_53, "Val_53", + Val_54, "Val_54", + Val_55, "Val_55", + Val_56, "Val_56", + Val_57, "Val_57", + Val_58, "Val_58", + Val_59, "Val_59", + Val_60, "Val_60", + Val_61, "Val_61", + Val_62, "Val_62", + Val_63, "Val_63", + Val_64, "Val_64", + Val_65, "Val_65", + Val_66, "Val_66", + Val_67, "Val_67", + Val_68, "Val_68", + Val_69, "Val_69", + Val_70, "Val_70", + Val_71, "Val_71", + Val_72, "Val_72", + Val_73, "Val_73", + Val_74, "Val_74", + Val_75, "Val_75", + Val_76, "Val_76", + Val_77, "Val_77", + Val_78, "Val_78", + Val_79, "Val_79", + Val_80, "Val_80", + Val_81, "Val_81", + Val_82, "Val_82", + Val_83, "Val_83", + Val_84, "Val_84", + Val_85, "Val_85", + Val_86, "Val_86", + Val_87, "Val_87", + Val_88, "Val_88", + Val_89, "Val_89", + Val_90, "Val_90", + Val_91, "Val_91", + Val_92, "Val_92", + Val_93, "Val_93", + Val_94, "Val_94", + Val_95, "Val_95", + Val_96, "Val_96", + Val_97, "Val_97", + Val_98, "Val_98", + Val_99, "Val_99", + Val_100, "Val_100", + Val_101, "Val_101", + Val_102, "Val_102", + Val_103, "Val_103", + Val_104, "Val_104", + Val_105, "Val_105", + Val_106, "Val_106", + Val_107, "Val_107", + Val_108, "Val_108", + Val_109, "Val_109", + Val_110, "Val_110", + Val_111, "Val_111", + Val_112, "Val_112", + Val_113, "Val_113", + Val_114, "Val_114", + Val_115, "Val_115", + Val_116, "Val_116", + Val_117, "Val_117", + Val_118, "Val_118", + Val_119, "Val_119", + Val_120, "Val_120", + Val_121, "Val_121", + Val_122, "Val_122", + Val_123, "Val_123", + Val_124, "Val_124", + Val_125, "Val_125", + Val_126, "Val_126", + Val_127, "Val_127", + Val_128, "Val_128", + Val_129, "Val_129", + Val_130, "Val_130" +}; + +static constexpr auto kOverflowTags2 = lcf::makeEnumTags( + "Val_0", + "Val_1", + "Val_2", + "Val_3", + "Val_4", + "Val_5", + "Val_6", + "Val_7", + "Val_8", + "Val_9", + "Val_10", + "Val_11", + "Val_12", + "Val_13", + "Val_14", + "Val_15", + "Val_16", + "Val_17", + "Val_18", + "Val_19", + "Val_20", + "Val_21", + "Val_22", + "Val_23", + "Val_24", + "Val_25", + "Val_26", + "Val_27", + "Val_28", + "Val_29", + "Val_30", + "Val_31", + "Val_32", + "Val_33", + "Val_34", + "Val_35", + "Val_36", + "Val_37", + "Val_38", + "Val_39", + "Val_40", + "Val_41", + "Val_42", + "Val_43", + "Val_44", + "Val_45", + "Val_46", + "Val_47", + "Val_48", + "Val_49", + "Val_50", + "Val_51", + "Val_52", + "Val_53", + "Val_54", + "Val_55", + "Val_56", + "Val_57", + "Val_58", + "Val_59", + "Val_60", + "Val_61", + "Val_62", + "Val_63", + "Val_64", + "Val_65", + "Val_66", + "Val_67", + "Val_68", + "Val_69", + "Val_70", + "Val_71", + "Val_72", + "Val_73", + "Val_74", + "Val_75", + "Val_76", + "Val_77", + "Val_78", + "Val_79", + "Val_80", + "Val_81", + "Val_82", + "Val_83", + "Val_84", + "Val_85", + "Val_86", + "Val_87", + "Val_88", + "Val_89", + "Val_90", + "Val_91", + "Val_92", + "Val_93", + "Val_94", + "Val_95", + "Val_96", + "Val_97", + "Val_98", + "Val_99", + "Val_100", + "Val_101", + "Val_102", + "Val_103", + "Val_104", + "Val_105", + "Val_106", + "Val_107", + "Val_108", + "Val_109", + "Val_110", + "Val_111", + "Val_112", + "Val_113", + "Val_114", + "Val_115", + "Val_116", + "Val_117", + "Val_118", + "Val_119", + "Val_120", + "Val_121", + "Val_122", + "Val_123", + "Val_124", + "Val_125", + "Val_126", + "Val_127", + "Val_128", + "Val_129", + "Val_130" +); + +TEST_CASE("makeEnumTags is same") { + REQUIRE_EQ(kColorTags.size(), kColorTags2.size()); + + auto s = kColorTags.size(); + + for (size_t i = 0; i < s; ++i) { + REQUIRE_EQ(kColorTags[i], kColorTags2[i]); + } + + REQUIRE_EQ(kOverflowTags.size(), kOverflowTags2.size()); + + s = kOverflowTags.size(); + + for (size_t i = 0; i < s; ++i) { + REQUIRE_EQ(kOverflowTags[i], kOverflowTags2[i]); + } +} + +TEST_CASE("8 Bit overflow") { + Overflow o; + + REQUIRE_EQ(kOverflowTags.size(), 131); + + REQUIRE(kOverflowTags.is_monotonic_from_zero()); + + REQUIRE(kOverflowTags.has_etag("Val_110")); + REQUIRE(kOverflowTags.has_etag("Val_130")); + + REQUIRE_EQ(kOverflowTags.tag(130), "Val_130"); + REQUIRE_EQ(kOverflowTags.tag(Val_130), "Val_130"); + + REQUIRE(kOverflowTags.etag("Val_130", o)); + REQUIRE_EQ(Val_130, o); +} + +TEST_SUITE_END();