-
Notifications
You must be signed in to change notification settings - Fork 869
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ads] Add SmartNTT numerical operator condition matcher
- Loading branch information
Showing
8 changed files
with
372 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
...condition_matcher/matchers/internal/numerical_operator_condition_matcher_util_internal.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "brave/components/brave_ads/core/internal/serving/targeting/condition_matcher/matchers/internal/numerical_operator_condition_matcher_util_internal.h" | ||
|
||
#include <cstddef> | ||
#include <string> | ||
|
||
#include "base/check.h" | ||
#include "base/logging.h" | ||
#include "base/strings/pattern.h" | ||
#include "base/strings/string_number_conversions.h" | ||
|
||
namespace brave_ads { | ||
|
||
std::optional<double> ParseNumber(const std::string_view condition) { | ||
CHECK(base::MatchPattern(condition, | ||
kNumericalOperatorConditionMatcherPrefixPattern)); | ||
|
||
const size_t pos = condition.find(':'); | ||
if (pos == std::string::npos || pos + 1 >= condition.size()) { | ||
// Malformed operator. | ||
VLOG(1) << "Malformed numerical operator condition matcher for " | ||
<< condition; | ||
return std::nullopt; | ||
} | ||
|
||
double number; | ||
if (!base::StringToDouble(condition.substr(pos + 1), &number)) { | ||
// Malformed number. | ||
VLOG(1) << "Malformed numerical operator condition matcher for " | ||
<< condition; | ||
return std::nullopt; | ||
} | ||
|
||
return number; | ||
} | ||
|
||
} // namespace brave_ads |
22 changes: 22 additions & 0 deletions
22
.../condition_matcher/matchers/internal/numerical_operator_condition_matcher_util_internal.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_SERVING_TARGETING_CONDITION_MATCHER_MATCHERS_INTERNAL_NUMERICAL_OPERATOR_CONDITION_MATCHER_UTIL_INTERNAL_H_ | ||
#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_SERVING_TARGETING_CONDITION_MATCHER_MATCHERS_INTERNAL_NUMERICAL_OPERATOR_CONDITION_MATCHER_UTIL_INTERNAL_H_ | ||
|
||
#include <optional> | ||
#include <string_view> | ||
|
||
namespace brave_ads { | ||
|
||
inline constexpr char kNumericalOperatorConditionMatcherPrefixPattern[] = | ||
"[R?]:*"; | ||
|
||
// Parses number from condition. | ||
std::optional<double> ParseNumber(std::string_view condition); | ||
|
||
} // namespace brave_ads | ||
|
||
#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_SERVING_TARGETING_CONDITION_MATCHER_MATCHERS_INTERNAL_NUMERICAL_OPERATOR_CONDITION_MATCHER_UTIL_INTERNAL_H_ |
47 changes: 47 additions & 0 deletions
47
..._matcher/matchers/internal/numerical_operator_condition_matcher_util_internal_unittest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "brave/components/brave_ads/core/internal/serving/targeting/condition_matcher/matchers/internal/numerical_operator_condition_matcher_util_internal.h" | ||
|
||
#include "brave/components/brave_ads/core/internal/common/test/test_base.h" | ||
|
||
// npm run test -- brave_unit_tests --filter=BraveAds* | ||
|
||
namespace brave_ads { | ||
|
||
class BraveAdsNumericalOperatorConditionMatcherUtilInternalTest | ||
: public test::TestBase {}; | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilInternalTest, | ||
ParseIntegerNumber) { | ||
// Act & Assert | ||
const std::optional<double> number = ParseNumber("[R=]:1"); | ||
ASSERT_TRUE(number); | ||
|
||
EXPECT_DOUBLE_EQ(1.0, *number); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilInternalTest, | ||
ParseDoubleNumber) { | ||
// Act & Assert | ||
const std::optional<double> number = ParseNumber("[R=]:1.0"); | ||
ASSERT_TRUE(number); | ||
|
||
EXPECT_DOUBLE_EQ(1.0, *number); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilInternalTest, | ||
DoNotParseMalformedNumber) { | ||
// Act & Assert | ||
EXPECT_FALSE(ParseNumber("[R=]: 1 ")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilInternalTest, | ||
DoNotParseInvalidNumber) { | ||
// Act & Assert | ||
EXPECT_FALSE(ParseNumber("[R=]:one")); | ||
} | ||
|
||
} // namespace brave_ads |
84 changes: 84 additions & 0 deletions
84
...serving/targeting/condition_matcher/matchers/numerical_operator_condition_matcher_util.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "brave/components/brave_ads/core/internal/serving/targeting/condition_matcher/matchers/numerical_operator_condition_matcher_util.h" | ||
|
||
#include <limits> | ||
#include <optional> | ||
|
||
#include "base/logging.h" | ||
#include "base/numerics/ranges.h" | ||
#include "base/strings/pattern.h" | ||
#include "base/strings/string_number_conversions.h" | ||
#include "brave/components/brave_ads/core/internal/serving/targeting/condition_matcher/matchers/internal/numerical_operator_condition_matcher_util_internal.h" | ||
|
||
namespace brave_ads { | ||
|
||
namespace { | ||
|
||
constexpr char kEqualOperatorConditionMatcherPrefix[] = "[R=]:"; | ||
constexpr char kNotEqualOperatorConditionMatcherPrefix[] = "[R≠]:"; | ||
constexpr char kGreaterThanOperatorConditionMatcherPrefix[] = "[R>]:"; | ||
constexpr char kGreaterThanOrEqualOperatorConditionMatcherPrefix[] = "[R≥]:"; | ||
constexpr char kLessThanOperatorConditionMatcherPrefix[] = "[R<]:"; | ||
constexpr char kLessThanOrEqualOperatorConditionMatcherPrefix[] = "[R≤]:"; | ||
|
||
} // namespace | ||
|
||
bool MatchNumericalOperator(const std::string_view value, | ||
const std::string_view condition) { | ||
if (!base::MatchPattern(condition, | ||
kNumericalOperatorConditionMatcherPrefixPattern)) { | ||
// Not an operator. | ||
return false; | ||
} | ||
|
||
const std::optional<double> number = ParseNumber(condition); | ||
if (!number) { | ||
// Invalid number. | ||
return false; | ||
} | ||
|
||
double value_as_double; | ||
if (!base::StringToDouble(value, &value_as_double)) { | ||
// Malformed value. | ||
VLOG(1) << "Malformed numerical operator condition matcher for " | ||
<< condition; | ||
return false; | ||
} | ||
|
||
if (condition.starts_with(kEqualOperatorConditionMatcherPrefix)) { | ||
return base::IsApproximatelyEqual(value_as_double, *number, | ||
std::numeric_limits<double>::epsilon()); | ||
} | ||
|
||
if (condition.starts_with(kNotEqualOperatorConditionMatcherPrefix)) { | ||
return !base::IsApproximatelyEqual(value_as_double, *number, | ||
std::numeric_limits<double>::epsilon()); | ||
} | ||
|
||
if (condition.starts_with(kGreaterThanOperatorConditionMatcherPrefix)) { | ||
return value_as_double > number; | ||
} | ||
|
||
if (condition.starts_with( | ||
kGreaterThanOrEqualOperatorConditionMatcherPrefix)) { | ||
return value_as_double >= number; | ||
} | ||
|
||
if (condition.starts_with(kLessThanOperatorConditionMatcherPrefix)) { | ||
return value_as_double < number; | ||
} | ||
|
||
if (condition.starts_with(kLessThanOrEqualOperatorConditionMatcherPrefix)) { | ||
return value_as_double <= number; | ||
} | ||
|
||
// Unknown operator. | ||
VLOG(1) << "Unknown numerical operator condition matcher for " << condition; | ||
return false; | ||
} | ||
|
||
} // namespace brave_ads |
20 changes: 20 additions & 0 deletions
20
.../serving/targeting/condition_matcher/matchers/numerical_operator_condition_matcher_util.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_SERVING_TARGETING_CONDITION_MATCHER_MATCHERS_NUMERICAL_OPERATOR_CONDITION_MATCHER_UTIL_H_ | ||
#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_SERVING_TARGETING_CONDITION_MATCHER_MATCHERS_NUMERICAL_OPERATOR_CONDITION_MATCHER_UTIL_H_ | ||
|
||
#include <string_view> | ||
|
||
namespace brave_ads { | ||
|
||
// Matches a value against a condition using numerical operators. Supports | ||
// equality, greater than, greater than or equal, less than, less than or equal | ||
// and not equal operators. | ||
bool MatchNumericalOperator(std::string_view value, std::string_view condition); | ||
|
||
} // namespace brave_ads | ||
|
||
#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_SERVING_TARGETING_CONDITION_MATCHER_MATCHERS_NUMERICAL_OPERATOR_CONDITION_MATCHER_UTIL_H_ |
152 changes: 152 additions & 0 deletions
152
...argeting/condition_matcher/matchers/numerical_operator_condition_matcher_util_unittest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
/* Copyright (c) 2024 The Brave Authors. All rights reserved. | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
* You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
|
||
#include "brave/components/brave_ads/core/internal/serving/targeting/condition_matcher/matchers/numerical_operator_condition_matcher_util.h" | ||
|
||
#include "brave/components/brave_ads/core/internal/common/test/test_base.h" | ||
|
||
// npm run test -- brave_unit_tests --filter=BraveAds* | ||
|
||
namespace brave_ads { | ||
|
||
class BraveAdsNumericalOperatorConditionMatcherUtilTest | ||
: public test::TestBase {}; | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchNonOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1", "baz")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchMalformedOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R=]: 1 ")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, MatchEqualOperator) { | ||
// Act & Assert | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R=]:1")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R=]:1")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R=]:1.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R=]:1.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchEqualOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R=]:2")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R=]:2")); | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R=]:2.0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R=]:2.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
MatchNotEqualOperator) { | ||
// Act & Assert | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≠]:2")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≠]:2")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≠]:2.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≠]:2.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchNotEqualOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R≠]:1")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R≠]:1")); | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R≠]:1.0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R≠]:1.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
MatchGreaterThanOperator) { | ||
// Act & Assert | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R>]:0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R>]:0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R>]:0.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R>]:0.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchGreaterThanOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R>]:1")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R>]:1")); | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R>]:1.0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R>]:1.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
MatchGreaterThanOrEqualOperator) { | ||
// Act & Assert | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≥]:0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≥]:0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≥]:0.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≥]:0.0")); | ||
|
||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≥]:1")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≥]:1")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≥]:1.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≥]:1.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchGreaterThanOrEqualOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R≥]:2")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R≥]:2")); | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R≥]:2.0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R≥]:2.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
MatchLessThanOperator) { | ||
// Act & Assert | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R<]:2")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R<]:2")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R<]:2.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R<]:2.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchLessThanOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R<]:1")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R<]:1")); | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R<]:1.0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R<]:1.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
MatchLessThanOrEqualOperator) { | ||
// Act & Assert | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≤]:1")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≤]:1")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≤]:1.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≤]:1.0")); | ||
|
||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≤]:2")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≤]:2")); | ||
EXPECT_TRUE(MatchNumericalOperator("1.0", "[R≤]:2.0")); | ||
EXPECT_TRUE(MatchNumericalOperator("1", "[R≤]:2.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchLessThanOrEqualOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R≤]:0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R≤]:0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1.0", "[R≤]:0.0")); | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[R≤]:0.0")); | ||
} | ||
|
||
TEST_F(BraveAdsNumericalOperatorConditionMatcherUtilTest, | ||
DoNotMatchUnknownOperator) { | ||
// Act & Assert | ||
EXPECT_FALSE(MatchNumericalOperator("1", "[_]:2")); | ||
} | ||
|
||
} // namespace brave_ads |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters