property.cpp (6272B)
1 #include "scraps/game/text_replace/text_replace_private.hpp" // IWYU pragma: associated 2 3 #include "scraps/game/character_state.hpp" 4 #include "scraps/game/game_state.hpp" 5 #include "scraps/game/object_state.hpp" // IWYU pragma: keep 6 #include "scraps/game/room_state.hpp" // IWYU pragma: keep 7 #include "scraps/game/timer_state.hpp" // IWYU pragma: keep 8 #include "scraps/game/variable_state.hpp" // IWYU pragma: keep 9 #include "scraps/string_utils.hpp" 10 #include "scraps/uuid.hpp" 11 12 #include <libshit/char_utils.hpp> 13 #include <libshit/doctest_std.hpp> 14 15 #include <optional> 16 17 #define LIBSHIT_LOG_NAME "text_replace" 18 #include <libshit/logger_helper.hpp> 19 20 // IWYU pragma: no_include <type_traits> 21 // IWYU pragma: no_forward_declare Scraps::Game::NameKey 22 // IWYU pragma: no_forward_declare Scraps::Game::UuidKey 23 24 namespace Scraps::Game::TextReplacePrivate 25 { 26 using namespace Libshit::NonowningStringLiterals; 27 TEST_SUITE_BEGIN("Scraps::Game::TextReplace"); 28 29 template <typename T> 30 static MacroRes GetGenProp( 31 MacroParam p, Libshit::StringView val, Libshit::StringView what, T fun) 32 { 33 auto colon0 = val.find_first_of(':'); 34 if (colon0 == Libshit::StringView::npos) return { ""_ns, p.macro.size() }; 35 auto name = Trim(val.substr(0, colon0)); 36 auto key = Trim( 37 val.substr(colon0 + 1, val.find_first_of(':', colon0 + 1) - colon0 - 1)); 38 39 auto r = fun(name); 40 if (!r.has_value()) 41 { 42 WARN << Libshit::Quoted(p.macro) << ": No such " << what << std::endl; 43 return { ""_ns, p.macro.size() }; 44 } 45 46 auto prop = r->GetProperties().Get(key); 47 if (!prop) 48 { 49 WARN << Libshit::Quoted(p.macro) << ": No such " << what << " property" 50 << std::endl; 51 return { ""_ns, p.macro.size() }; 52 } 53 54 if (p.new_value) 55 { 56 // need to copy the old value out since Set *might* invalidate the old sv 57 p.tmp_str.assign(prop->second); 58 PropertiesProxy{ProxyConstCast{}, r->GetProperties()}. 59 Set(key, p.new_value->to_string()); 60 return { p.tmp_str, p.macro.size() }; 61 } 62 return { prop->second, p.macro.size() }; 63 } 64 65 template <typename T> 66 static MacroRes GetSimpleProp( 67 MacroParam p, Libshit::StringView val, Libshit::StringView what, 68 const T& coll) 69 { 70 return GetGenProp( 71 p, val, what, [&](Libshit::StringView name) 72 { return coll.template Get<NameKey>(name); }); 73 } 74 75 template <typename T> 76 static MacroRes GetUuidProp( 77 MacroParam p, Libshit::StringView val, Libshit::StringView what, 78 const T& coll) 79 { 80 return GetGenProp(p, val, what, [&](Libshit::StringView name) 81 -> decltype(coll.template Get<NameKey>(name)) 82 { 83 if (auto paren = name.find_first_of('('); paren != Libshit::StringView::npos) 84 { 85 auto uuid = Uuid::TryParse(name.substr(0, paren)); if (!uuid) return {}; 86 return coll.template Get<UuidKey>(*uuid); 87 } 88 else 89 return coll.template Get<NameKey>(name); 90 }); 91 } 92 93 MacroRes GetCharacterProp(MacroParam p, Libshit::StringView val) 94 { return GetSimpleProp(p, val, "character", p.gs.GetCharacterColl()); } 95 96 MacroRes GetObjectProp(MacroParam p, Libshit::StringView val) 97 { return GetUuidProp(p, val, "object", p.gs.GetObjectColl()); } 98 99 MacroRes GetPlayerProp(MacroParam p, Libshit::StringView val) 100 { 101 auto x = p.gs.GetPlayer().GetProperties().Get(Trim(val)); 102 return { x ? x->second : ""_ns, p.macro.size() }; 103 } 104 105 MacroRes GetRoomProp(MacroParam p, Libshit::StringView val) 106 { return GetUuidProp(p, val, "room", p.gs.GetRoomColl()); } 107 108 MacroRes GetTimerProp(MacroParam p, Libshit::StringView val) 109 { return GetSimpleProp(p, val, "timer", p.gs.GetTimerColl()); } 110 111 MacroRes GetVariableProp(MacroParam p, Libshit::StringView val) 112 { 113 return GetGenProp( 114 p, val, "variable", [&](Libshit::StringView name) 115 { 116 return p.gs.GetVariableColl().Get<NameKey>( 117 StripIndexFromVariableName(name)); 118 }); 119 } 120 121 TEST_CASE_FIXTURE(MacroFixture, "properties") 122 { 123 #define RP(str) GetRoomProp(COLON_ARGS("rp", str, {})) 124 // valid 125 CHECK(RP("room_0:key_0") == MacroRes{"Value 0", 17}); 126 CHECK(RP(" room_0 : key_0 ") == MacroRes{"Value 0", 21}); 127 CHECK(RP("roOM_0:Key_0") == MacroRes{"Value 0", 17}); 128 CHECK(RP("00000000-0000-4004-0000-000000000001(:key_0") == 129 MacroRes{"Value 0", 48}); 130 CHECK(RP("00000000-0000-4004-0000-000000000001 (:key_0") == 131 MacroRes{"Value 0", 49}); 132 CHECK(RP("room_0:key_0:garbage") == MacroRes{"Value 0", 25}); 133 134 // invalid 135 CHECK(RP("room_0:key_z") == MacroRes{"", 17}); 136 CHECK(RP("room_z:key_0") == MacroRes{"", 17}); 137 CHECK(RP("00000000-0000-4004-0000000000000001(:key_0") == MacroRes{"", 47}); 138 CHECK(RP("foo") == MacroRes{"", 8}); 139 #undef RP 140 141 // object is pretty much the same as room 142 CHECK(GetObjectProp(COLON_ARGS("ip", "object_0:key_1", {})) == 143 MacroRes{"Value 1", 19}); 144 145 // and the simple ones 146 CHECK(GetCharacterProp(COLON_ARGS("cp", "chara_0:key_0", {})) == 147 MacroRes{"Value 0", 18}); 148 CHECK(GetVariableProp(COLON_ARGS("vp", " Var_0 : Key_1 ", {})) == 149 MacroRes{"Value 1", 20}); 150 CHECK(GetVariableProp(COLON_ARGS("vp", " Var_0(foo : Key_1 ", {})) == 151 MacroRes{"Value 1", 24}); 152 CHECK(GetTimerProp(COLON_ARGS("tp", "timeR_0 : Key_0", {})) == 153 MacroRes{"Value 0", 20}); 154 CHECK(GetTimerProp(COLON_ARGS("tp", "timer_0:no", {})) == MacroRes{"", 15}); 155 CHECK(GetTimerProp(COLON_ARGS("tp", "no:key_0", {})) == MacroRes{"", 13}); 156 157 // player is completely different 158 #define PP(str) GetPlayerProp(COLON_ARGS("pp", str, {})) 159 CHECK(PP("key_0") == MacroRes{"Value 0", 10}); 160 CHECK(PP(" Key_1 ") == MacroRes{"Value 1", 12}); 161 CHECK(PP("no") == MacroRes{"", 7}); 162 CHECK(PP("key_0:") == MacroRes{"", 11}); 163 #undef PP 164 165 // set tests 166 auto props = gs.GetCharacterColl().At(0).GetProperties(); 167 CHECK(GetCharacterProp(COLON_ARGS("cp", "chara_0:key_0", "new")) == 168 MacroRes{"Value 0", 18}); 169 CHECK(props.Get("key_0").value().second == "new"); 170 CHECK(GetCharacterProp(COLON_ARGS("cp", "chara_0:key_0", "other")) == 171 MacroRes{"new", 18}); 172 CHECK(props.Get("key_0").value().second == "other"); 173 } 174 175 TEST_SUITE_END(); 176 }