mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-24 10:23:02 -07:00
[Filter] Restore exact, case-insensitive set code search (#7336)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
* [Filter] Restore exact, case-insensitive set code search (#7332, #7333) * [Filter] Group set query suffix modes into a subrule Address review feedback: keep the 'e'/'set' prefix in one place and move the three suffix modes (exact, negated, release-date comparison) into a dedicated choice-like rule so sv.choice() still dispatches on them. Add coverage for the release-date comparison mode. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
7a2492ac67
commit
e2a4556546
2 changed files with 97 additions and 3 deletions
|
|
@ -20,7 +20,8 @@ SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
|
||||||
QueryPart <- NotQuery / SetQuery / RarityQuery / CMCQuery / FormatQuery / PowerQuery / ToughnessQuery / ColorQuery / TypeQuery / OracleQuery / FieldQuery / GenericQuery
|
QueryPart <- NotQuery / SetQuery / RarityQuery / CMCQuery / FormatQuery / PowerQuery / ToughnessQuery / ColorQuery / TypeQuery / OracleQuery / FieldQuery / GenericQuery
|
||||||
|
|
||||||
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
||||||
SetQuery <- ('e'/'set') SetExpression / ([:] FlexStringValue)
|
SetQuery <- ('e'/'set') SetQueryValue
|
||||||
|
SetQueryValue <- ([=:] FlexStringValue) / (<[!][=]?> FlexStringValue) / SetExpression
|
||||||
OracleQuery <- 'o' [:] MatcherString
|
OracleQuery <- 'o' [:] MatcherString
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -133,8 +134,8 @@ static void setupParserRules()
|
||||||
const auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
const auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
||||||
return [=](const CardData &x) -> bool { return matcher(x->getCardType()); };
|
return [=](const CardData &x) -> bool { return matcher(x->getCardType()); };
|
||||||
};
|
};
|
||||||
search["SetQuery"] = [](const peg::SemanticValues &sv) -> Filter {
|
search["SetQueryValue"] = [](const peg::SemanticValues &sv) -> Filter {
|
||||||
if (sv.choice() == 1) {
|
if (sv.choice() == 0) {
|
||||||
auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
||||||
return [=](const CardData &x) -> bool {
|
return [=](const CardData &x) -> bool {
|
||||||
QList<QString> sets = x->getSets().keys();
|
QList<QString> sets = x->getSets().keys();
|
||||||
|
|
@ -143,6 +144,15 @@ static void setupParserRules()
|
||||||
return std::any_of(sets.begin(), sets.end(), matchesSet);
|
return std::any_of(sets.begin(), sets.end(), matchesSet);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (sv.choice() == 1) {
|
||||||
|
auto matcher = std::any_cast<StringMatcher>(sv[0]);
|
||||||
|
return [=](const CardData &x) -> bool {
|
||||||
|
QList<QString> sets = x->getSets().keys();
|
||||||
|
|
||||||
|
auto matchesSet = [&matcher](const QString &set) { return matcher(set); };
|
||||||
|
return std::none_of(sets.begin(), sets.end(), matchesSet);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
auto matcher = std::any_cast<NumberMatcher>(sv[0]);
|
auto matcher = std::any_cast<NumberMatcher>(sv[0]);
|
||||||
return [=](const CardData &x) -> bool {
|
return [=](const CardData &x) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
#include "test_card_database_path_provider.h"
|
#include "test_card_database_path_provider.h"
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include <libcockatrice/card/card_info.h>
|
||||||
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
#include <libcockatrice/card/printing/printing_info.h>
|
||||||
#include <libcockatrice/filters/filter_string.h>
|
#include <libcockatrice/filters/filter_string.h>
|
||||||
#include <libcockatrice/interfaces/noop_card_preference_provider.h>
|
#include <libcockatrice/interfaces/noop_card_preference_provider.h>
|
||||||
#include <libcockatrice/interfaces/noop_card_set_priority_controller.h>
|
#include <libcockatrice/interfaces/noop_card_set_priority_controller.h>
|
||||||
|
|
@ -71,6 +74,13 @@ QUERY(Color2, cat, "c:gw", true)
|
||||||
QUERY(Color3, cat, "c!g", true)
|
QUERY(Color3, cat, "c!g", true)
|
||||||
QUERY(Color4, cat, "c!gw", false)
|
QUERY(Color4, cat, "c!gw", false)
|
||||||
|
|
||||||
|
QUERY(SetCodeCaseInsensitive1, cat, "set:cat", true)
|
||||||
|
QUERY(SetCodeCaseInsensitive2, cat, "set:CAT", true)
|
||||||
|
QUERY(SetCodeCaseInsensitive3, cat, "set:CAt", true)
|
||||||
|
QUERY(SetCodeShortForm, cat, "e:cat", true)
|
||||||
|
QUERY(SetCodeWrongSet, cat, "set:who", false)
|
||||||
|
QUERY(SetCodeWrongSet2, doctor, "set:cat", false)
|
||||||
|
|
||||||
QUERY(BracketNextToUnquotedString, cat, "(o:woof OR o:meow)", true)
|
QUERY(BracketNextToUnquotedString, cat, "(o:woof OR o:meow)", true)
|
||||||
|
|
||||||
CardInfoPtr localizedCat()
|
CardInfoPtr localizedCat()
|
||||||
|
|
@ -126,6 +136,80 @@ TEST_F(CardQuery, SearchLanguageIsBoundPerInstance)
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
class SetQuery : public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
// EOE and EOC share a release date, like a set and its Commander counterpart.
|
||||||
|
const QDate sharedReleaseDate(2026, 3, 13);
|
||||||
|
mainSet = CardSet::newInstance(&controller, "EOE", "Edge of Eternities", "expansion", sharedReleaseDate,
|
||||||
|
CardSet::PriorityPrimary);
|
||||||
|
commanderSet = CardSet::newInstance(&controller, "EOC", "Edge of Eternities Commander", "commander",
|
||||||
|
sharedReleaseDate, CardSet::PrioritySecondary);
|
||||||
|
oldSet = CardSet::newInstance(&controller, "OLD", "Older Set", "expansion", QDate(2020, 1, 1),
|
||||||
|
CardSet::PriorityPrimary);
|
||||||
|
|
||||||
|
inBothSets = newCardWithPrintings({{"EOE", mainSet}, {"EOC", commanderSet}});
|
||||||
|
onlyInCommanderSet = newCardWithPrintings({{"EOC", commanderSet}});
|
||||||
|
onlyInOldSet = newCardWithPrintings({{"OLD", oldSet}});
|
||||||
|
|
||||||
|
// SetExpression resolves set codes to release dates through the global set list.
|
||||||
|
auto *database = CardDatabaseManager::getInstance();
|
||||||
|
database->addSet(mainSet);
|
||||||
|
database->addSet(commanderSet);
|
||||||
|
database->addSet(oldSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
CardInfoPtr newCardWithPrintings(const QList<QPair<QString, CardSetPtr>> &printings)
|
||||||
|
{
|
||||||
|
SetToPrintingsMap setsInfo;
|
||||||
|
for (const auto &printing : printings) {
|
||||||
|
setsInfo[printing.first].append(PrintingInfo(printing.second));
|
||||||
|
}
|
||||||
|
return CardInfo::newInstance("Test Card", "", false, {}, {}, {}, setsInfo, CardInfo::UiAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
NoopCardSetPriorityController controller;
|
||||||
|
CardSetPtr mainSet;
|
||||||
|
CardSetPtr commanderSet;
|
||||||
|
CardSetPtr oldSet;
|
||||||
|
CardInfoPtr inBothSets;
|
||||||
|
CardInfoPtr onlyInCommanderSet;
|
||||||
|
CardInfoPtr onlyInOldSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(SetQuery, ExactMatchSeparatesSameDaySets)
|
||||||
|
{
|
||||||
|
EXPECT_TRUE(FilterString("set:EOE").check(inBothSets));
|
||||||
|
EXPECT_TRUE(FilterString("e:EOE").check(inBothSets));
|
||||||
|
EXPECT_TRUE(FilterString("set:EOC").check(inBothSets));
|
||||||
|
EXPECT_FALSE(FilterString("set:EOE").check(onlyInCommanderSet));
|
||||||
|
EXPECT_TRUE(FilterString("set:EOC").check(onlyInCommanderSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SetQuery, ExactMatchIsCaseInsensitive)
|
||||||
|
{
|
||||||
|
EXPECT_TRUE(FilterString("set:eoe").check(inBothSets));
|
||||||
|
EXPECT_TRUE(FilterString("set:EoE").check(inBothSets));
|
||||||
|
EXPECT_FALSE(FilterString("set:eoe").check(onlyInCommanderSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SetQuery, NotEqualsMatchesPrintingsOutsideTheSet)
|
||||||
|
{
|
||||||
|
EXPECT_FALSE(FilterString("set!EOE").check(inBothSets));
|
||||||
|
EXPECT_TRUE(FilterString("set!EOE").check(onlyInCommanderSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SetQuery, ComparisonMatchesByReleaseDate)
|
||||||
|
{
|
||||||
|
// OLD (2020) predates EOE/EOC (2026-03-13), so comparison operators still use release dates.
|
||||||
|
EXPECT_TRUE(FilterString("set<EOE").check(onlyInOldSet));
|
||||||
|
EXPECT_FALSE(FilterString("set>EOE").check(onlyInOldSet));
|
||||||
|
EXPECT_TRUE(FilterString("set>=EOE").check(inBothSets));
|
||||||
|
EXPECT_FALSE(FilterString("set<EOE").check(inBothSets));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue