mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-08 19:13:25 -08:00
Merge e540126056 into df74917cb0
This commit is contained in:
commit
a37a494ce7
12 changed files with 464 additions and 131 deletions
|
|
@ -15,9 +15,58 @@
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <libcockatrice/filters/filter_tree.h>
|
#include <libcockatrice/filters/filter_tree.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter
|
* @brief Information about the behaviour of a filter mode.
|
||||||
* model.
|
*/
|
||||||
|
struct FilterModeInfo
|
||||||
|
{
|
||||||
|
// When a color symbol is enabled, add filters of this type. Skipped if equal to CardFilter::Type::TypeEnd.
|
||||||
|
CardFilter::Type includeType;
|
||||||
|
|
||||||
|
// When a color symbol is disabled, add filters of this type. Skipped if equal to CardFilter::Type::TypeEnd.
|
||||||
|
CardFilter::Type excludeType;
|
||||||
|
|
||||||
|
// The attribute to filter for when adding the filters.
|
||||||
|
CardFilter::Attr attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Return information about the given filter mode. */
|
||||||
|
static FilterModeInfo getFilterModeInfo(FilterMode filterMode)
|
||||||
|
{
|
||||||
|
switch (filterMode) {
|
||||||
|
case FilterMode::Includes:
|
||||||
|
return {CardFilter::Type::TypeOr, CardFilter::Type::TypeEnd, CardFilter::Attr::AttrColor};
|
||||||
|
case FilterMode::Excludes:
|
||||||
|
return {CardFilter::Type::TypeAndNot, CardFilter::Type::TypeEnd, CardFilter::Attr::AttrColor};
|
||||||
|
case FilterMode::IncludeExclude:
|
||||||
|
return {CardFilter::Type::TypeOr, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor};
|
||||||
|
case FilterMode::ExactMatch:
|
||||||
|
return {CardFilter::Type::TypeAnd, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor};
|
||||||
|
case FilterMode::ColorIdentity:
|
||||||
|
return {CardFilter::Type::TypeEnd, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColorIdentity};
|
||||||
|
case FilterMode::Custom:
|
||||||
|
case FilterMode::End:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return {CardFilter::Type::TypeEnd, CardFilter::Type::TypeEnd, CardFilter::Attr::AttrEnd};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Remove the filters that apply to the given color and attribute from the given model. */
|
||||||
|
static void removeFilters(FilterTreeModel *filterModel, QChar color, CardFilter::Attr attr)
|
||||||
|
{
|
||||||
|
for (const CardFilter *filter : filterModel->getFiltersOfType(attr)) {
|
||||||
|
if (filter->term() == color) {
|
||||||
|
filterModel->removeFilter(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor and
|
||||||
|
* CardFilter::Attr::AttrColorIdentity filters applied to the filter model.
|
||||||
* @param parent The Qt Widget that this widget will parent to
|
* @param parent The Qt Widget that this widget will parent to
|
||||||
* @param _filterModel The filter model that this widget will manipulate
|
* @param _filterModel The filter model that this widget will manipulate
|
||||||
*/
|
*/
|
||||||
|
|
@ -59,11 +108,25 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
|
||||||
modeComboBox->blockSignals(true);
|
modeComboBox->blockSignals(true);
|
||||||
modeComboBox->clear();
|
modeComboBox->clear();
|
||||||
|
|
||||||
modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch));
|
|
||||||
modeComboBox->addItem(tr("Includes"), QVariant::fromValue(FilterMode::Includes));
|
modeComboBox->addItem(tr("Includes"), QVariant::fromValue(FilterMode::Includes));
|
||||||
|
modeComboBox->addItem(tr("Excludes"), QVariant::fromValue(FilterMode::Excludes));
|
||||||
modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude));
|
modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude));
|
||||||
|
modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch));
|
||||||
|
modeComboBox->addItem(tr("Color identity"), QVariant::fromValue(FilterMode::ColorIdentity));
|
||||||
|
|
||||||
|
modeComboBox->setItemData(0, tr("Cards containing any of the selected colors"), Qt::ToolTipRole);
|
||||||
|
modeComboBox->setItemData(1, tr("Cards containing none of the selected colors"), Qt::ToolTipRole);
|
||||||
|
modeComboBox->setItemData(2, tr("Cards containing any of the selected colors and none of the unselected colors"),
|
||||||
|
Qt::ToolTipRole);
|
||||||
|
modeComboBox->setItemData(3, tr("Cards being exactly of the selected colors"), Qt::ToolTipRole);
|
||||||
|
modeComboBox->setItemData(4, tr("Cards whose color identity fits within the selected colors"), Qt::ToolTipRole);
|
||||||
|
|
||||||
|
if (currentMode == FilterMode::Custom) {
|
||||||
|
addCustomFilterModeItem();
|
||||||
|
}
|
||||||
|
|
||||||
modeComboBox->setToolTip(tr("How selected and unselected colors are combined in the filter"));
|
modeComboBox->setToolTip(tr("How selected and unselected colors are combined in the filter"));
|
||||||
|
modeComboBox->setAccessibleName(tr("Color filter mode"));
|
||||||
|
|
||||||
// Restore current mode
|
// Restore current mode
|
||||||
const int index = modeComboBox->findData(QVariant::fromValue(currentMode));
|
const int index = modeComboBox->findData(QVariant::fromValue(currentMode));
|
||||||
|
|
@ -74,6 +137,28 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
|
||||||
modeComboBox->blockSignals(false);
|
modeComboBox->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayColorFilterWidget::setFilterMode(FilterMode filterMode)
|
||||||
|
{
|
||||||
|
int index = modeComboBox->findData(QVariant::fromValue(filterMode));
|
||||||
|
|
||||||
|
if (index < 0 && filterMode == FilterMode::Custom) {
|
||||||
|
index = modeComboBox->count();
|
||||||
|
addCustomFilterModeItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
modeComboBox->setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayColorFilterWidget::addCustomFilterModeItem()
|
||||||
|
{
|
||||||
|
int customIndex = modeComboBox->count();
|
||||||
|
modeComboBox->addItem(tr("Custom"), QVariant::fromValue(FilterMode::Custom));
|
||||||
|
modeComboBox->setItemData(customIndex, tr("Cards matching an unknown combination of color filters"),
|
||||||
|
Qt::ToolTipRole);
|
||||||
|
}
|
||||||
|
|
||||||
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
|
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
|
||||||
{
|
{
|
||||||
if (active) {
|
if (active) {
|
||||||
|
|
@ -85,74 +170,24 @@ void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, boo
|
||||||
|
|
||||||
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color)
|
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color)
|
||||||
{
|
{
|
||||||
QString colorString = color;
|
FilterModeInfo info = getFilterModeInfo(currentMode);
|
||||||
QString typeStr;
|
|
||||||
|
|
||||||
// Remove previous filters
|
removeFilters(filterModel, color, info.attr);
|
||||||
|
|
||||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
if (info.includeType != CardFilter::Type::TypeEnd) {
|
||||||
QList<const CardFilter *> matchingFilters;
|
filterModel->addFilter(new CardFilter(color, info.includeType, info.attr));
|
||||||
|
|
||||||
for (const CardFilter *filter : allColorFilters) {
|
|
||||||
if (filter->term() == color) {
|
|
||||||
matchingFilters.append(filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const CardFilter *filter : matchingFilters) {
|
|
||||||
filterModel->removeFilter(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add actual filter
|
|
||||||
|
|
||||||
switch (currentMode) {
|
|
||||||
case FilterMode::ExactMatch:
|
|
||||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterMode::Includes:
|
|
||||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterMode::IncludeExclude:
|
|
||||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color)
|
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color)
|
||||||
{
|
{
|
||||||
QString colorString = color;
|
FilterModeInfo info = getFilterModeInfo(currentMode);
|
||||||
|
|
||||||
// Remove inclusion filters
|
removeFilters(filterModel, color, info.attr);
|
||||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
|
||||||
QList<const CardFilter *> matchingFilters;
|
|
||||||
|
|
||||||
for (const CardFilter *filter : allColorFilters) {
|
// Add exclusion filters if the mode demands it.
|
||||||
if (filter->term() == color) {
|
if (info.excludeType != CardFilter::Type::TypeEnd) {
|
||||||
matchingFilters.append(filter);
|
filterModel->addFilter(new CardFilter(color, info.excludeType, info.attr));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const CardFilter *filter : matchingFilters) {
|
|
||||||
filterModel->removeFilter(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add exclusion filters if the mode demands it
|
|
||||||
switch (currentMode) {
|
|
||||||
case FilterMode::ExactMatch:
|
|
||||||
filterModel->addFilter(
|
|
||||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterMode::IncludeExclude:
|
|
||||||
filterModel->addFilter(
|
|
||||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterMode::Includes:
|
|
||||||
// No exclusion in Includes mode
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,6 +204,7 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
|
||||||
filterModel->filterTree()->blockSignals(true);
|
filterModel->filterTree()->blockSignals(true);
|
||||||
|
|
||||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
|
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
|
||||||
|
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColorIdentity);
|
||||||
|
|
||||||
const QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
const QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||||
|
|
||||||
|
|
@ -211,52 +247,94 @@ QList<QChar> VisualDatabaseDisplayColorFilterWidget::getActiveColors()
|
||||||
|
|
||||||
void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
|
void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
|
||||||
{
|
{
|
||||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
// Determine the correct currentMode from the filter model by finding which modes
|
||||||
|
// are not possible due to the model containing (a combination of) filters that
|
||||||
|
// that mode cannot add.
|
||||||
|
constexpr int modeCount = static_cast<int>(FilterMode::End);
|
||||||
|
bool modeImpossible[modeCount] = {};
|
||||||
|
|
||||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
QList<const CardFilter *> filters;
|
||||||
|
filters.append(filterModel->getFiltersOfType(CardFilter::Attr::AttrColor));
|
||||||
|
filters.append(filterModel->getFiltersOfType(CardFilter::Attr::AttrColorIdentity));
|
||||||
|
|
||||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
for (int i = 0; i < modeCount; ++i) {
|
||||||
bool found = false;
|
FilterModeInfo modeInfo = getFilterModeInfo(static_cast<FilterMode>(i));
|
||||||
for (const CardFilter *filter : allColorFilters) {
|
|
||||||
if (manaSymbolWidget->getSymbolChar() == filter->term()) {
|
// Remove the modes that cannot create one of the filters.
|
||||||
switch (currentMode) {
|
for (const CardFilter *filter : filters) {
|
||||||
case FilterMode::ExactMatch:
|
if (filter->attr() != modeInfo.attr ||
|
||||||
switch (filter->type()) {
|
(filter->type() != modeInfo.includeType && filter->type() != modeInfo.excludeType)) {
|
||||||
case CardFilter::Type::TypeAnd:
|
modeImpossible[i] = true;
|
||||||
setManaSymbolActive(filter->term().at(0), true);
|
break;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setManaSymbolActive(filter->term().at(0), false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FilterMode::Includes:
|
|
||||||
switch (filter->type()) {
|
|
||||||
case CardFilter::Type::TypeOr:
|
|
||||||
setManaSymbolActive(filter->term().at(0), true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setManaSymbolActive(filter->term().at(0), false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FilterMode::IncludeExclude:
|
|
||||||
switch (filter->type()) {
|
|
||||||
case CardFilter::Type::TypeOr:
|
|
||||||
setManaSymbolActive(filter->term().at(0), true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setManaSymbolActive(filter->term().at(0), false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
// Modes that have both an include and exclude filter should always have a filter for each color.
|
||||||
setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false);
|
if (modeInfo.includeType != CardFilter::Type::TypeEnd && modeInfo.excludeType != CardFilter::Type::TypeEnd &&
|
||||||
|
!modeImpossible[i]) {
|
||||||
|
for (const QChar &color : QString("WUBRG")) {
|
||||||
|
int count = 0;
|
||||||
|
for (const CardFilter *filter : filters) {
|
||||||
|
count += filter->term() == color;
|
||||||
|
}
|
||||||
|
if (count != 1) {
|
||||||
|
modeImpossible[i] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the current mode is not possible with the current filters, set it to the first
|
||||||
|
// one that is. Switching to and from the custom mode is always possible.
|
||||||
|
if (modeImpossible[static_cast<int>(currentMode)] || currentMode == FilterMode::Custom) {
|
||||||
|
for (int i = 0; i < modeCount; ++i) {
|
||||||
|
if (!modeImpossible[i] || i == static_cast<int>(FilterMode::Custom)) {
|
||||||
|
currentMode = static_cast<FilterMode>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the combobox. Add a Custom item only if we have a custom filter mode.
|
||||||
|
int customIndex = modeComboBox->findData(QVariant::fromValue(FilterMode::Custom));
|
||||||
|
modeComboBox->blockSignals(true);
|
||||||
|
if (currentMode == FilterMode::Custom) {
|
||||||
|
if (customIndex < 0) {
|
||||||
|
customIndex = modeComboBox->count();
|
||||||
|
addCustomFilterModeItem();
|
||||||
|
}
|
||||||
|
modeComboBox->setCurrentIndex(customIndex);
|
||||||
|
} else {
|
||||||
|
if (customIndex >= 0) {
|
||||||
|
modeComboBox->removeItem(customIndex);
|
||||||
|
}
|
||||||
|
int index = modeComboBox->findData(QVariant::fromValue(currentMode));
|
||||||
|
if (index >= 0) {
|
||||||
|
modeComboBox->setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modeComboBox->blockSignals(false);
|
||||||
|
|
||||||
|
// Update the mana symbol widgets by looking for the current mode's include or exclude filters.
|
||||||
|
const FilterModeInfo modeInfo = getFilterModeInfo(currentMode);
|
||||||
|
|
||||||
|
const bool useExclude =
|
||||||
|
modeInfo.includeType == CardFilter::Type::TypeEnd && modeInfo.excludeType != CardFilter::Type::TypeEnd;
|
||||||
|
const CardFilter::Type filterType = useExclude ? modeInfo.excludeType : modeInfo.includeType;
|
||||||
|
|
||||||
|
filters = filterModel->getFiltersOfType(modeInfo.attr);
|
||||||
|
|
||||||
|
for (ManaSymbolWidget *manaSymbolWidget : findChildren<ManaSymbolWidget *>()) {
|
||||||
|
bool found = false;
|
||||||
|
for (const CardFilter *filter : filters) {
|
||||||
|
if (filter->type() == filterType && manaSymbolWidget->getSymbolChar() == filter->term()) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manaSymbolWidget->setColorActive(useExclude ? !found : found);
|
||||||
|
manaSymbolWidget->setDisabled(currentMode == FilterMode::Custom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,14 @@ private:
|
||||||
|
|
||||||
enum class FilterMode
|
enum class FilterMode
|
||||||
{
|
{
|
||||||
ExactMatch, // Only selected colors are included, all others are excluded.
|
Includes = 0, // Include selected colors (OR condition).
|
||||||
Includes, // Include selected colors (OR condition).
|
Excludes, // Exclude selected colors (AND NOT).
|
||||||
IncludeExclude // Include selected colors (OR) and exclude unselected colors (AND NOT).
|
IncludeExclude, // Include selected colors (OR) and exclude unselected colors (AND NOT).
|
||||||
|
ExactMatch, // Only selected colors are included, all others are excluded.
|
||||||
|
ColorIdentity, // Keep cards whose color identity is a subset of the selected colors (stored as AND NOT for each
|
||||||
|
// unselected color).
|
||||||
|
Custom, // The color filters do not match any of the above modes. Not included in the combo box.
|
||||||
|
End
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(FilterMode)
|
Q_DECLARE_METATYPE(FilterMode)
|
||||||
|
|
@ -54,11 +59,13 @@ class VisualDatabaseDisplayColorFilterWidget : public QWidget
|
||||||
public:
|
public:
|
||||||
explicit VisualDatabaseDisplayColorFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
|
explicit VisualDatabaseDisplayColorFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
void setFilterMode(FilterMode filterMode);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void filterModeChanged(FilterMode filterMode);
|
void filterModeChanged(FilterMode filterMode);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void addCustomFilterModeItem();
|
||||||
void handleColorToggled(QChar color, bool active);
|
void handleColorToggled(QChar color, bool active);
|
||||||
void addFilter(QChar color);
|
void addFilter(QChar color);
|
||||||
void removeFilter(QChar color);
|
void removeFilter(QChar color);
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,7 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
|
||||||
connect(clearFilterWidget, &QToolButton::clicked, this, [this] {
|
connect(clearFilterWidget, &QToolButton::clicked, this, [this] {
|
||||||
filterModel->blockSignals(true);
|
filterModel->blockSignals(true);
|
||||||
filterModel->filterTree()->blockSignals(true);
|
filterModel->filterTree()->blockSignals(true);
|
||||||
|
colorFilterWidget->setFilterMode(FilterMode::Includes);
|
||||||
filterModel->clear();
|
filterModel->clear();
|
||||||
filterModel->blockSignals(false);
|
filterModel->blockSignals(false);
|
||||||
filterModel->filterTree()->blockSignals(false);
|
filterModel->filterTree()->blockSignals(false);
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,10 @@ void CardInfo::setColors(const QString &value)
|
||||||
{
|
{
|
||||||
setProperty(Mtg::Colors, value);
|
setProperty(Mtg::Colors, value);
|
||||||
}
|
}
|
||||||
|
QString CardInfo::getColorIdentity() const
|
||||||
|
{
|
||||||
|
return getProperty(Mtg::ColorIdentity);
|
||||||
|
}
|
||||||
QString CardInfo::getLoyalty() const
|
QString CardInfo::getLoyalty() const
|
||||||
{
|
{
|
||||||
return getProperty(Mtg::Loyalty);
|
return getProperty(Mtg::Loyalty);
|
||||||
|
|
|
||||||
|
|
@ -469,6 +469,7 @@ public:
|
||||||
[[nodiscard]] QString getCmc() const;
|
[[nodiscard]] QString getCmc() const;
|
||||||
[[nodiscard]] QString getColors() const;
|
[[nodiscard]] QString getColors() const;
|
||||||
void setColors(const QString &value);
|
void setColors(const QString &value);
|
||||||
|
[[nodiscard]] QString getColorIdentity() const;
|
||||||
[[nodiscard]] QString getLoyalty() const;
|
[[nodiscard]] QString getLoyalty() const;
|
||||||
[[nodiscard]] QString getMainCardType() const;
|
[[nodiscard]] QString getMainCardType() const;
|
||||||
[[nodiscard]] QString getManaCost() const;
|
[[nodiscard]] QString getManaCost() const;
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ const QString CardFilter::attrName(Attr a)
|
||||||
return tr("Type");
|
return tr("Type");
|
||||||
case AttrColor:
|
case AttrColor:
|
||||||
return tr("Color");
|
return tr("Color");
|
||||||
|
case AttrColorIdentity:
|
||||||
|
return tr("Color Identity");
|
||||||
case AttrText:
|
case AttrText:
|
||||||
return tr("Text");
|
return tr("Text");
|
||||||
case AttrSet:
|
case AttrSet:
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ public:
|
||||||
{
|
{
|
||||||
AttrCmc = 0,
|
AttrCmc = 0,
|
||||||
AttrColor,
|
AttrColor,
|
||||||
|
AttrColorIdentity,
|
||||||
AttrLoyalty,
|
AttrLoyalty,
|
||||||
AttrManaCost,
|
AttrManaCost,
|
||||||
AttrName,
|
AttrName,
|
||||||
|
|
|
||||||
|
|
@ -409,7 +409,7 @@ static void setupParserRules()
|
||||||
const bool identity = sv.tokens[0].empty() || sv.tokens[0][0] != 'i';
|
const bool identity = sv.tokens[0].empty() || sv.tokens[0][0] != 'i';
|
||||||
if (sv.tokens[1][0] == ':') {
|
if (sv.tokens[1][0] == ':') {
|
||||||
return [=](const CardData &x) {
|
return [=](const CardData &x) {
|
||||||
const QString match = identity ? x->getColors() : x->getProperty("coloridentity");
|
const QString match = identity ? x->getColors() : x->getColorIdentity();
|
||||||
if (parts.contains("m") && match.length() < 2) {
|
if (parts.contains("m") && match.length() < 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -427,7 +427,7 @@ static void setupParserRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
return [=](const CardData &x) {
|
return [=](const CardData &x) {
|
||||||
const QString match = identity ? x->getColors() : x->getProperty("colorIdentity");
|
const QString match = identity ? x->getColors() : x->getColorIdentity();
|
||||||
if (parts.contains("m") && match.length() < 2) {
|
if (parts.contains("m") && match.length() < 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,23 +176,24 @@ FilterItem::FilterItem(QString trm, FilterItemList *parent) : p(parent), term(st
|
||||||
lowercaseTerm = term.toLower();
|
lowercaseTerm = term.toLower();
|
||||||
|
|
||||||
switch (attr()) {
|
switch (attr()) {
|
||||||
case CardFilter::AttrColor: {
|
case CardFilter::AttrColor:
|
||||||
QString converted = term.trimmed();
|
case CardFilter::AttrColorIdentity: {
|
||||||
|
QString converted = term.trimmed().toLower();
|
||||||
|
|
||||||
converted.replace("green", "g", Qt::CaseInsensitive);
|
converted.replace("green", "g");
|
||||||
converted.replace("grn", "g", Qt::CaseInsensitive);
|
converted.replace("grn", "g");
|
||||||
converted.replace("blue", "u", Qt::CaseInsensitive);
|
converted.replace("blue", "u");
|
||||||
converted.replace("blu", "u", Qt::CaseInsensitive);
|
converted.replace("blu", "u");
|
||||||
converted.replace("black", "b", Qt::CaseInsensitive);
|
converted.replace("black", "b");
|
||||||
converted.replace("blk", "b", Qt::CaseInsensitive);
|
converted.replace("blk", "b");
|
||||||
converted.replace("red", "r", Qt::CaseInsensitive);
|
converted.replace("red", "r");
|
||||||
converted.replace("white", "w", Qt::CaseInsensitive);
|
converted.replace("white", "w");
|
||||||
converted.replace("wht", "w", Qt::CaseInsensitive);
|
converted.replace("wht", "w");
|
||||||
converted.replace("colorless", "c", Qt::CaseInsensitive);
|
converted.replace("colorless", "c");
|
||||||
converted.replace("colourless", "c", Qt::CaseInsensitive);
|
converted.replace("colourless", "c");
|
||||||
converted.replace("none", "c", Qt::CaseInsensitive);
|
converted.replace("none", "c");
|
||||||
|
|
||||||
converted.replace(QString(" "), QString(""), Qt::CaseInsensitive);
|
converted.replace(QString(" "), QString(""));
|
||||||
|
|
||||||
convertedColorTerm = converted;
|
convertedColorTerm = converted;
|
||||||
break;
|
break;
|
||||||
|
|
@ -358,12 +359,17 @@ bool FilterItem::acceptSubType(const CardInfoPtr &info) const
|
||||||
return subType.contains(term, Qt::CaseInsensitive);
|
return subType.contains(term, Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilterItem::acceptColor(const CardInfoPtr &info) const
|
/**
|
||||||
|
* @brief Return true when every letter of the given term appears in the given colors string.
|
||||||
|
* If the term is equal to "c", then only return true if the color string is empty.
|
||||||
|
*
|
||||||
|
* @param term The letters which should be included, or "c"
|
||||||
|
* @param colors The string to check for letters in
|
||||||
|
*/
|
||||||
|
static bool matchesColor(const QString &term, const QString &colors)
|
||||||
{
|
{
|
||||||
const QString colors = info->getColors();
|
|
||||||
|
|
||||||
// Colorless card filter
|
// Colorless card filter
|
||||||
if (convertedColorTerm.toLower() == "c" && colors.length() < 1) {
|
if (term == "c" && colors.length() < 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -372,13 +378,23 @@ bool FilterItem::acceptColor(const CardInfoPtr &info) const
|
||||||
* then we should match all of them to the card's colors
|
* then we should match all of them to the card's colors
|
||||||
*/
|
*/
|
||||||
int match_count = 0;
|
int match_count = 0;
|
||||||
for (const QChar &color : convertedColorTerm) {
|
for (const QChar &color : term) {
|
||||||
if (colors.contains(color, Qt::CaseInsensitive)) {
|
if (colors.contains(color, Qt::CaseInsensitive)) {
|
||||||
match_count++;
|
match_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return match_count == convertedColorTerm.length();
|
return match_count == term.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FilterItem::acceptColor(const CardInfoPtr &info) const
|
||||||
|
{
|
||||||
|
return matchesColor(convertedColorTerm, info->getColors());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FilterItem::acceptColorIdentity(const CardInfoPtr &info) const
|
||||||
|
{
|
||||||
|
return matchesColor(convertedColorTerm, info->getColorIdentity());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilterItem::acceptText(const CardInfoPtr &info, const CardSearchLanguage &searchLanguage) const
|
bool FilterItem::acceptText(const CardInfoPtr &info, const CardSearchLanguage &searchLanguage) const
|
||||||
|
|
@ -540,6 +556,8 @@ bool FilterItem::acceptCardAttr(const CardInfoPtr &info,
|
||||||
return acceptType(info);
|
return acceptType(info);
|
||||||
case CardFilter::AttrColor:
|
case CardFilter::AttrColor:
|
||||||
return acceptColor(info);
|
return acceptColor(info);
|
||||||
|
case CardFilter::AttrColorIdentity:
|
||||||
|
return acceptColorIdentity(info);
|
||||||
case CardFilter::AttrText:
|
case CardFilter::AttrText:
|
||||||
return acceptText(info, searchLanguage);
|
return acceptText(info, searchLanguage);
|
||||||
case CardFilter::AttrSet:
|
case CardFilter::AttrSet:
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,7 @@ public:
|
||||||
[[nodiscard]] bool acceptMainType(const CardInfoPtr &info) const;
|
[[nodiscard]] bool acceptMainType(const CardInfoPtr &info) const;
|
||||||
[[nodiscard]] bool acceptSubType(const CardInfoPtr &info) const;
|
[[nodiscard]] bool acceptSubType(const CardInfoPtr &info) const;
|
||||||
[[nodiscard]] bool acceptColor(const CardInfoPtr &info) const;
|
[[nodiscard]] bool acceptColor(const CardInfoPtr &info) const;
|
||||||
|
[[nodiscard]] bool acceptColorIdentity(const CardInfoPtr &info) const;
|
||||||
[[nodiscard]] bool acceptText(const CardInfoPtr &info, const CardSearchLanguage &searchLanguage) const;
|
[[nodiscard]] bool acceptText(const CardInfoPtr &info, const CardSearchLanguage &searchLanguage) const;
|
||||||
[[nodiscard]] bool acceptSet(const CardInfoPtr &info) const;
|
[[nodiscard]] bool acceptSet(const CardInfoPtr &info) const;
|
||||||
[[nodiscard]] bool acceptManaCost(const CardInfoPtr &info) const;
|
[[nodiscard]] bool acceptManaCost(const CardInfoPtr &info) const;
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,12 @@ cockatrice_add_test(
|
||||||
)
|
)
|
||||||
|
|
||||||
# ------------------------
|
# ------------------------
|
||||||
# Filter String Test
|
# Guard to match condition for libcockatrice_filters in the root CMakeLists.txt
|
||||||
# (guard must match the condition for libcockatrice_filters in the root CMakeLists.txt)
|
|
||||||
# ------------------------
|
# ------------------------
|
||||||
if(WITH_ORACLE OR WITH_CLIENT)
|
if(WITH_ORACLE OR WITH_CLIENT)
|
||||||
|
# ------------------------
|
||||||
|
# Filter String Test
|
||||||
|
# ------------------------
|
||||||
cockatrice_add_test(
|
cockatrice_add_test(
|
||||||
NAME
|
NAME
|
||||||
filter_string_test
|
filter_string_test
|
||||||
|
|
@ -36,6 +38,20 @@ if(WITH_ORACLE OR WITH_CLIENT)
|
||||||
libcockatrice_filters
|
libcockatrice_filters
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Filter Tree Test
|
||||||
|
# ------------------------
|
||||||
|
cockatrice_add_test(
|
||||||
|
NAME
|
||||||
|
filter_tree_test
|
||||||
|
SOURCES
|
||||||
|
${VERSION_STRING_CPP}
|
||||||
|
filter_tree_test.cpp
|
||||||
|
mocks.cpp
|
||||||
|
LIBS
|
||||||
|
libcockatrice_filters
|
||||||
|
)
|
||||||
|
|
||||||
# ------------------------
|
# ------------------------
|
||||||
# Visual Display Model Test
|
# Visual Display Model Test
|
||||||
# ------------------------
|
# ------------------------
|
||||||
|
|
|
||||||
204
tests/carddatabase/filter_tree_test.cpp
Normal file
204
tests/carddatabase/filter_tree_test.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
|
||||||
|
#include "libcockatrice/filters/filter_tree.h"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <libcockatrice/card/card_localization.h>
|
||||||
|
#include <libcockatrice/filters/filter_string.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class FilterTreeTest : public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
language = CardSearchLanguage{};
|
||||||
|
|
||||||
|
island = CardInfo::newInstance("Island", "", false, {{"colors", ""}, {"coloridentity", "U"}}, {}, {}, {}, {});
|
||||||
|
artifact =
|
||||||
|
CardInfo::newInstance("Artifact", "", false, {{"colors", ""}, {"coloridentity", ""}}, {}, {}, {}, {});
|
||||||
|
truth = CardInfo::newInstance("Truth", "", false, {{"colors", "U"}, {"coloridentity", "U"}}, {}, {}, {}, {});
|
||||||
|
notDead =
|
||||||
|
CardInfo::newInstance("Not Dead", "", false, {{"colors", "B"}, {"coloridentity", "B"}}, {}, {}, {}, {});
|
||||||
|
wallOfDenial = CardInfo::newInstance("Wall of Denial", "", false, {{"colors", "WU"}, {"coloridentity", "WU"}},
|
||||||
|
{}, {}, {}, {});
|
||||||
|
maelstromAngel = CardInfo::newInstance("Maelstrom Archangel", "", false,
|
||||||
|
{{"colors", "WUBRG"}, {"coloridentity", "WUBRG"}}, {}, {}, {}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
CardSearchLanguage language;
|
||||||
|
|
||||||
|
CardData island; // c/u
|
||||||
|
CardData artifact; // c
|
||||||
|
CardData truth; // u
|
||||||
|
CardData notDead; // b
|
||||||
|
CardData wallOfDenial; // wu
|
||||||
|
CardData maelstromAngel; // wubrg
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
// acceptColor
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, Color)
|
||||||
|
{
|
||||||
|
FilterTree filterTree;
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "wu");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(island, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(artifact, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, ColorColorless)
|
||||||
|
{
|
||||||
|
FilterTree filterTree;
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "c");
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(island, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, ColorNot)
|
||||||
|
{
|
||||||
|
FilterTree filterTree;
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAndNot, "b");
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(island, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, ColorAliases)
|
||||||
|
{
|
||||||
|
FilterTree filterTree;
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "green");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "grn");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "blue");
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "blu");
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "black");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(notDead, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "blk");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(notDead, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "red");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "white");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "wht");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "colorless");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "colourless");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
filterTree.clear();
|
||||||
|
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColor, CardFilter::Type::TypeAnd, "none");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
filterTree.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
// acceptColorIdentity
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, ColorIdentity)
|
||||||
|
{
|
||||||
|
FilterTree filterTree;
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColorIdentity, CardFilter::Type::TypeAnd, "wu");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(island, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(artifact, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, ColorIdentityColorless)
|
||||||
|
{
|
||||||
|
FilterTree filterTree;
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColorIdentity, CardFilter::Type::TypeAnd, "c");
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(island, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, ColorIdentityNot)
|
||||||
|
{
|
||||||
|
FilterTree filterTree;
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColorIdentity, CardFilter::Type::TypeAndNot, "b");
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(island, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FilterTreeTest, ColorIdentityMultiple)
|
||||||
|
{
|
||||||
|
// Simulate a WU commander.
|
||||||
|
FilterTree filterTree;
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColorIdentity, CardFilter::Type::TypeAndNot, "b");
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColorIdentity, CardFilter::Type::TypeAndNot, "r");
|
||||||
|
filterTree.termNode(CardFilter::Attr::AttrColorIdentity, CardFilter::Type::TypeAndNot, "g");
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(island, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(artifact, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(truth, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(notDead, language));
|
||||||
|
ASSERT_TRUE(filterTree.acceptsCard(wallOfDenial, language));
|
||||||
|
ASSERT_FALSE(filterTree.acceptsCard(maelstromAngel, language));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue