diff --git a/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util.cc b/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util.cc index cb7ed61773f0..b844d4298131 100644 --- a/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util.cc +++ b/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util.cc @@ -15,6 +15,14 @@ namespace brave_ads { namespace { +constexpr char kNotOperatorPrefix[] = "[!]:"; + +std::string NormalizePrefPath(const std::string& pref_path) { + return pref_path.starts_with(kNotOperatorPrefix) + ? pref_path.substr(/*pos=*/std::strlen(kNotOperatorPrefix)) + : pref_path; +} + bool MatchCondition(const std::string_view value, const std::string_view condition) { return MatchOperator(value, condition) || MatchPattern(value, condition) || @@ -32,15 +40,18 @@ bool MatchConditions( condition_matchers, [pref_provider](const auto& condition_matcher) { const auto& [pref_path, condition] = condition_matcher; + // If `has_not_operator` is `true`, it means that the condition should + // match if the pref path does not exist. + const bool has_not_operator = pref_path.starts_with(kNotOperatorPrefix); + const std::string normalized_pref_path = NormalizePrefPath(pref_path); if (const std::optional value = MaybeGetPrefValueAsString( pref_provider, normalized_pref_path)) { - return MatchCondition(*value, condition); + return !has_not_operator && MatchCondition(*value, condition); } - // Do not serve the ad due to an unknown preference path or - // unsupported value type. - return false; + // Unknown pref path. + return has_not_operator; }); } diff --git a/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util_unittest.cc b/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util_unittest.cc index 8755921336b2..9df14cf18771 100644 --- a/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util_unittest.cc +++ b/components/brave_ads/core/internal/serving/new_tab_page_ad_serving_condition_matcher_util_unittest.cc @@ -124,6 +124,16 @@ TEST_F(BraveAdsNewTabPageAdServingConditionMatcherUtilTest, EXPECT_FALSE(MatchConditions(&pref_provider_, condition_matchers)); } +TEST_F(BraveAdsNewTabPageAdServingConditionMatcherUtilTest, + MatchConditionsWithNotOperatorWhenPrefPathNotFound) { + // Arrange + const NewTabPageAdConditionMatcherMap condition_matchers = { + {"[!]:foo.bar", "baz"}}; + + // Act & Assert + EXPECT_TRUE(MatchConditions(&pref_provider_, condition_matchers)); +} + TEST_F(BraveAdsNewTabPageAdServingConditionMatcherUtilTest, DoNotMatchConditionsIfAllConditionsAreFalse) { // Arrange