From d2262ebaecb16a74b110b32db11b5e53942b3db8 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 28 Dec 2021 11:49:42 +0100 Subject: [PATCH] Fix menu dvarStrList not working because of String chaining --- .../Menu/Matcher/MenuMatcherFactory.cpp | 5 + .../Parsing/Menu/Matcher/MenuMatcherFactory.h | 1 + .../Menu/Sequence/ItemScopeSequences.cpp | 4 +- .../Menu/Sequence/ItemScopeSequencesTests.cpp | 91 +++++++++++++++++++ 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 test/ObjLoadingTests/Parsing/Menu/Sequence/ItemScopeSequencesTests.cpp diff --git a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp index e6833691..07b7189b 100644 --- a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp +++ b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.cpp @@ -37,6 +37,11 @@ MatcherFactoryWrapper MenuMatcherFactory::Text() const return MatcherFactoryWrapper(Or({StringChain(), Identifier()})); } +MatcherFactoryWrapper MenuMatcherFactory::TextNoChain() const +{ + return MatcherFactoryWrapper(Or({String(), Identifier()})); +} + MatcherFactoryWrapper MenuMatcherFactory::Numeric() const { return MatcherFactoryWrapper(Or({FloatingPoint(), Integer()})); diff --git a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h index d21838f4..d965c5ec 100644 --- a/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h +++ b/src/ObjLoading/Parsing/Menu/Matcher/MenuMatcherFactory.h @@ -20,6 +20,7 @@ namespace menu _NODISCARD MatcherFactoryWrapper StringChain() const; _NODISCARD MatcherFactoryWrapper Text() const; + _NODISCARD MatcherFactoryWrapper TextNoChain() const; _NODISCARD MatcherFactoryWrapper Numeric() const; _NODISCARD MatcherFactoryWrapper IntExpression() const; diff --git a/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp b/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp index 12666917..2a7d12f0 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp +++ b/src/ObjLoading/Parsing/Menu/Sequence/ItemScopeSequences.cpp @@ -362,9 +362,9 @@ namespace menu::item_scope_sequences create.KeywordIgnoreCase("dvarStrList").Capture(CAPTURE_FIRST_TOKEN), create.Char('{'), create.OptionalLoop(create.And({ - create.Text().Capture(CAPTURE_STEP_NAME), + create.TextNoChain().Capture(CAPTURE_STEP_NAME), create.Optional(create.Char(';')), - create.Text().Capture(CAPTURE_STEP_VALUE), + create.TextNoChain().Capture(CAPTURE_STEP_VALUE), create.Optional(create.Char(';')), })), create.Char('}') diff --git a/test/ObjLoadingTests/Parsing/Menu/Sequence/ItemScopeSequencesTests.cpp b/test/ObjLoadingTests/Parsing/Menu/Sequence/ItemScopeSequencesTests.cpp new file mode 100644 index 00000000..9262db82 --- /dev/null +++ b/test/ObjLoadingTests/Parsing/Menu/Sequence/ItemScopeSequencesTests.cpp @@ -0,0 +1,91 @@ +#include + +#include "Utils/ClassUtils.h" +#include "Parsing/Menu/Sequence/ItemScopeSequences.h" +#include "Parsing/Mock/MockLexer.h" + +using namespace menu; + +namespace test::parsing::menu::sequence::item +{ + class ItemSequenceTestsHelper + { + public: + std::vector> m_all_sequences; + std::vector m_scope_sequences; + std::unique_ptr m_state; + std::unique_ptr> m_lexer; + + std::unique_ptr m_item; + + unsigned m_consumed_token_count; + + explicit ItemSequenceTestsHelper(FeatureLevel featureLevel, const bool permissive) + : m_state(std::make_unique(featureLevel, false)), + m_item(std::make_unique()), + m_consumed_token_count(0u) + { + ItemScopeSequences scopeSequences(m_all_sequences, m_scope_sequences); + scopeSequences.AddSequences(m_state->m_feature_level, permissive); + + m_state->m_current_menu = m_state->m_menus.emplace_back(std::make_unique()).get(); + m_state->m_current_item = m_item.get(); + } + + void Tokens(std::initializer_list> tokens) + { + m_lexer = std::make_unique>(tokens, SimpleParserValue::EndOfFile(TokenPos())); + } + + void Tokens(std::vector tokens) + { + m_lexer = std::make_unique>(std::move(tokens), SimpleParserValue::EndOfFile(TokenPos())); + } + + bool PerformTest() + { + REQUIRE(m_lexer); + + m_consumed_token_count = 0; + for (const auto* sequence : m_scope_sequences) + { + const auto couldMatch = sequence->MatchSequence(m_lexer.get(), m_state.get(), m_consumed_token_count); + if (couldMatch) + { + m_lexer->PopTokens(static_cast(m_consumed_token_count)); + return couldMatch; + } + } + + return false; + } + }; + + TEST_CASE("ItemScopeSequences: Simple dvarStrList works", "[parsing][sequence][menu]") + { + ItemSequenceTestsHelper helper(FeatureLevel::IW4, false); + const TokenPos pos; + helper.Tokens({ + SimpleParserValue::Identifier(pos, new std::string("dvarStrList")), + SimpleParserValue::Character(pos, '{'), + SimpleParserValue::String(pos, new std::string("@MENU_AUTO")), + SimpleParserValue::String(pos, new std::string("auto")), + SimpleParserValue::String(pos, new std::string("@MENU_STANDARD_4_3")), + SimpleParserValue::String(pos, new std::string("standard")), + SimpleParserValue::String(pos, new std::string("@MENU_WIDE_16_10")), + SimpleParserValue::String(pos, new std::string("wide 16:10")), + SimpleParserValue::String(pos, new std::string("@MENU_WIDE_16_9")), + SimpleParserValue::String(pos, new std::string("wide 16:9")), + SimpleParserValue::Character(pos, '}'), + SimpleParserValue::EndOfFile(pos) + }); + + helper.m_item->m_feature_type = CommonItemFeatureType::MULTI_VALUE; + helper.m_item->m_multi_value_features = std::make_unique(); + + const auto result = helper.PerformTest(); + + REQUIRE(result); + REQUIRE(helper.m_consumed_token_count == 11); + } +}