From 86f5fd377854d03538bda29be21e15c8383f2200 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Fri, 14 Aug 2026 16:57:12 +0200 Subject: [PATCH] Add possibility to use piped attributes for comparison --- libs/rtemodel/src/RteCondition.cpp | 2 +- libs/rtemodel/test/src/RteConditionTest.cpp | 43 +++++++++++++++++++++ libs/rteutils/include/WildCards.h | 8 ++++ libs/rteutils/src/WildCards.cpp | 35 +++++++++++++++++ libs/rteutils/test/src/RteUtilsTest.cpp | 24 ++++++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) diff --git a/libs/rtemodel/src/RteCondition.cpp b/libs/rtemodel/src/RteCondition.cpp index e66991c0e..fda306406 100644 --- a/libs/rtemodel/src/RteCondition.cpp +++ b/libs/rtemodel/src/RteCondition.cpp @@ -235,7 +235,7 @@ RteItem::ConditionResult RteConditionExpression::EvaluateExpression(RteTarget* t continue; } // all other attributes - if(!WildCards::Match(va, v)) + if(!WildCards::MatchAny(va, v)) return FAILED; } else if(GetExpressionType() == DENY) { return FAILED; // for denied attributes, all must be given diff --git a/libs/rtemodel/test/src/RteConditionTest.cpp b/libs/rtemodel/test/src/RteConditionTest.cpp index edf4967b2..e6677d603 100644 --- a/libs/rtemodel/test/src/RteConditionTest.cpp +++ b/libs/rtemodel/test/src/RteConditionTest.cpp @@ -47,6 +47,49 @@ TEST(RteConditionValidateTest, Validate) EXPECT_FALSE(deviceExpression.Validate()); } +TEST_F(RteConditionTest, PipeSeparatedWildcardEvaluation) { + RteKernelSlim rteKernel; + rteKernel.SetCmsisPackRoot(RteModelTestConfig::CMSIS_PACK_ROOT); + RteCprjProject* loadedCprjProject = rteKernel.LoadCprj(RteTestM3_cprj); + ASSERT_NE(loadedCprjProject, nullptr); + EXPECT_TRUE(loadedCprjProject->Validate()); + + RteTarget* activeTarget = loadedCprjProject->GetActiveTarget(); + ASSERT_NE(activeTarget, nullptr); + RteConditionContext* filterContext = activeTarget->GetFilterContext(); + ASSERT_NE(filterContext, nullptr); + + RteRequireExpression deviceExpression(nullptr); + deviceExpression.AddAttribute("Dname", "DoesNotMatch|RteTest_ARMCM?"); + deviceExpression.ConstructID(); + EXPECT_EQ(deviceExpression.Evaluate(filterContext), RteItem::FULFILLED); + + deviceExpression.SetAttribute("Dname", "DoesNotMatch|RteTest_ARMCM4"); + EXPECT_EQ(deviceExpression.Evaluate(filterContext), RteItem::FAILED); + + activeTarget->SetAttribute("Tcompiler", "ARMCC|GCC"); + + RteRequireExpression armccExpression(nullptr); + armccExpression.AddAttribute("Tcompiler", "ARMCC"); + armccExpression.ConstructID(); + EXPECT_EQ(armccExpression.Evaluate(filterContext), RteItem::FULFILLED); + + RteRequireExpression gccExpression(nullptr); + gccExpression.AddAttribute("Tcompiler", "GCC"); + gccExpression.ConstructID(); + EXPECT_EQ(gccExpression.Evaluate(filterContext), RteItem::FULFILLED); + + RteRequireExpression alternativeCompilerExpression(nullptr); + alternativeCompilerExpression.AddAttribute("Tcompiler", "XC|GCC"); + alternativeCompilerExpression.ConstructID(); + EXPECT_EQ(alternativeCompilerExpression.Evaluate(filterContext), RteItem::FULFILLED); + + RteRequireExpression unsupportedCompilerExpression(nullptr); + unsupportedCompilerExpression.AddAttribute("Tcompiler", "XC"); + unsupportedCompilerExpression.ConstructID(); + EXPECT_EQ(unsupportedCompilerExpression.Evaluate(filterContext), RteItem::FAILED); +} + TEST_F(RteConditionTest, MissingIgnoredFulfilledSelectable) { // load project to get a working target and condition contexts RteKernelSlim rteKernel; diff --git a/libs/rteutils/include/WildCards.h b/libs/rteutils/include/WildCards.h index df5aed569..4fd2be1bd 100644 --- a/libs/rteutils/include/WildCards.h +++ b/libs/rteutils/include/WildCards.h @@ -42,6 +42,14 @@ class WildCards */ static bool Match(const std::string& s1, const std::string& s2); + /** + * @brief match any pair of non-empty, pipe-separated strings + * @param s1 pipe-separated strings to be matched, can contain wild card patterns + * @param s2 pipe-separated strings to be matched, can contain wild card patterns + * @return true if any pair of strings matches, otherwise false + */ + static bool MatchAny(const std::string& s1, const std::string& s2); + /** * @brief converts "*" to ".*" and "?" to "." * @param s string to be converted diff --git a/libs/rteutils/src/WildCards.cpp b/libs/rteutils/src/WildCards.cpp index c01d74ba3..67dc4fa25 100644 --- a/libs/rteutils/src/WildCards.cpp +++ b/libs/rteutils/src/WildCards.cpp @@ -13,6 +13,8 @@ /******************************************************************************/ #include "WildCards.h" +#include "RteUtils.h" + #include @@ -38,6 +40,39 @@ bool WildCards::Match(const std::string& s1, const std::string& s2) return false; } +bool WildCards::MatchAny(const std::string& s1, const std::string& s2) +{ + // first compare strings as is to save time by further match + if (s1 == s2) { + return true; + } + + if (s1.empty() || s2.empty()) { + return false; + } + + + std::list alternatives1; + std::list alternatives2; + RteUtils::SplitString(alternatives1, s1, '|'); + RteUtils::SplitString(alternatives2, s2, '|'); + + for (const auto& alternative1 : alternatives1) { + if (alternative1.empty()) { + continue; + } + for (const auto& alternative2 : alternatives2) { + if (alternative2.empty()) { + continue; + } + if (Match(alternative1, alternative2)) { + return true; + } + } + } + return false; +} + std::string WildCards::ToRegEx(const std::string& s) { // Char translations: diff --git a/libs/rteutils/test/src/RteUtilsTest.cpp b/libs/rteutils/test/src/RteUtilsTest.cpp index af68e8ffc..4a94a22e4 100644 --- a/libs/rteutils/test/src/RteUtilsTest.cpp +++ b/libs/rteutils/test/src/RteUtilsTest.cpp @@ -226,6 +226,7 @@ TEST(RteUtilsTest, WildCardsTo) { } TEST(RteUtilsTest, WildCardMatch) { + EXPECT_EQ(true, WildCards::Match("", "")); EXPECT_EQ(true, WildCards::Match("a", "a")); EXPECT_EQ(false, WildCards::Match("a", "")); EXPECT_EQ(false, WildCards::Match("", "d")); @@ -286,6 +287,29 @@ TEST(RteUtilsTest, WildCardMatch) { } } +TEST(RteUtilsTest, WildCardMatchAny) { + EXPECT_TRUE(WildCards::MatchAny("", "")); + EXPECT_TRUE(WildCards::MatchAny("*", "*")); + EXPECT_TRUE(WildCards::MatchAny("foo", "foo")); + EXPECT_TRUE(WildCards::MatchAny("foo*", "foo")); + EXPECT_TRUE(WildCards::MatchAny("foo*", "foo*")); + EXPECT_TRUE(WildCards::MatchAny("foo|bar", "bar")); + EXPECT_TRUE(WildCards::MatchAny("bar", "foo|bar")); + EXPECT_FALSE(WildCards::MatchAny("foo|bar", "baz|qux")); + + EXPECT_TRUE(WildCards::MatchAny("foo*|bar", "food|baz")); + EXPECT_TRUE(WildCards::MatchAny("food|baz", "foo*|bar")); + EXPECT_TRUE(WildCards::MatchAny("foo?|bar", "f*|baz")); + EXPECT_TRUE(WildCards::MatchAny("foo", "foo")); + + EXPECT_TRUE(WildCards::MatchAny("|foo||bar|", "||bar|")); + EXPECT_FALSE(WildCards::MatchAny("|foo||bar|", "||baz|")); + EXPECT_FALSE(WildCards::MatchAny("", "foo")); + EXPECT_FALSE(WildCards::MatchAny("foo", "")); + + EXPECT_FALSE(WildCards::Match("foo|bar", "bar")); +} + TEST(RteUtilsTest, AlnumCmp_Char) { EXPECT_EQ( -1, AlnumCmp::Compare(nullptr, "2.1")); EXPECT_EQ( 1, AlnumCmp::Compare("10.1", nullptr));