Commit de7cc438 authored by Matthias Körber's avatar Matthias Körber Committed by Commit Bot

[Autofill][Slimshady] Added a provider for enumerated regular

expressions.

This utility class lazily builds the patterns, compiles and caches
enumerated regular expressions that are used for parsing and matching.

The justification for this is that it becomes unnecessary to
repeatedly rebuild patterns and pass them around the code.
Further, a future integration of a component updater
to change the patterns behind on of the expressions becomes minimally
invasive.

Change-Id: Icb7082e504603b43358a6d84f853e7b5336c3cad
Bug: 1099202
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2299632
Commit-Queue: Matthias Körber <koerber@google.com>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790415}
parent 72533cd9
...@@ -90,6 +90,10 @@ jumbo_static_library("browser") { ...@@ -90,6 +90,10 @@ jumbo_static_library("browser") {
"data_model/autofill_profile_comparator.h", "data_model/autofill_profile_comparator.h",
"data_model/autofill_structured_address_component.cc", "data_model/autofill_structured_address_component.cc",
"data_model/autofill_structured_address_component.h", "data_model/autofill_structured_address_component.h",
"data_model/autofill_structured_address_constants.cc",
"data_model/autofill_structured_address_constants.h",
"data_model/autofill_structured_address_regex_provider.cc",
"data_model/autofill_structured_address_regex_provider.h",
"data_model/autofill_structured_address_utils.cc", "data_model/autofill_structured_address_utils.cc",
"data_model/autofill_structured_address_utils.h", "data_model/autofill_structured_address_utils.h",
"data_model/contact_info.cc", "data_model/contact_info.cc",
...@@ -571,6 +575,7 @@ source_set("unit_tests") { ...@@ -571,6 +575,7 @@ source_set("unit_tests") {
"data_model/autofill_profile_comparator_unittest.cc", "data_model/autofill_profile_comparator_unittest.cc",
"data_model/autofill_profile_unittest.cc", "data_model/autofill_profile_unittest.cc",
"data_model/autofill_structured_address_component_unittest.cc", "data_model/autofill_structured_address_component_unittest.cc",
"data_model/autofill_structured_address_regex_provider_unittest.cc",
"data_model/autofill_structured_address_utils_unittest.cc", "data_model/autofill_structured_address_utils_unittest.cc",
"data_model/contact_info_unittest.cc", "data_model/contact_info_unittest.cc",
"data_model/credit_card_unittest.cc", "data_model/credit_card_unittest.cc",
......
...@@ -307,8 +307,8 @@ bool AddressComponent::ParseValueAndAssignSubcomponentsByMethod() { ...@@ -307,8 +307,8 @@ bool AddressComponent::ParseValueAndAssignSubcomponentsByMethod() {
return false; return false;
} }
std::vector<const RE2*> AddressComponent::GetParseExpressionsByRelevance() std::vector<const RE2*>
const { AddressComponent::GetParseRegularExpressionsByRelevance() const {
return {}; return {};
} }
...@@ -323,15 +323,15 @@ void AddressComponent::ParseValueAndAssignSubcomponents() { ...@@ -323,15 +323,15 @@ void AddressComponent::ParseValueAndAssignSubcomponents() {
return; return;
// Second attempt, try to parse by expressions. // Second attempt, try to parse by expressions.
if (ParseValueAndAssignSubcomponentsByExpressions()) if (ParseValueAndAssignSubcomponentsByRegularExpressions())
return; return;
// As a final fallback, parse using the fallback method. // As a final fallback, parse using the fallback method.
ParseValueAndAssignSubcomponentsByFallbackMethod(); ParseValueAndAssignSubcomponentsByFallbackMethod();
} }
bool AddressComponent::ParseValueAndAssignSubcomponentsByExpressions() { bool AddressComponent::ParseValueAndAssignSubcomponentsByRegularExpressions() {
for (const auto* parse_expression : GetParseExpressionsByRelevance()) { for (const auto* parse_expression : GetParseRegularExpressionsByRelevance()) {
if (!parse_expression) if (!parse_expression)
continue; continue;
std::map<std::string, std::string> result_map; std::map<std::string, std::string> result_map;
......
...@@ -197,9 +197,9 @@ class AddressComponent { ...@@ -197,9 +197,9 @@ class AddressComponent {
// to catch special cases and may fail. The method is virtual and can be // to catch special cases and may fail. The method is virtual and can be
// implemented on the type level. // implemented on the type level.
// //
// * Use |ParseValueAndAssignSubcomponentsByExpressions()|. This stage uses a // * Use |ParseValueAndAssignSubcomponentsByRegularExpressions()|. This stage
// list of regular expressions acquired by the virtual method // uses a list of regular expressions acquired by the virtual method
// |GetParseExpressionsByRelevance()|. This stage my fail. // |GetParseRegularExpressionsByRelevance()|. This stage my fail.
// //
// * Use |ParseValueAndAssignSubcomponentsByFallbackMethod()| as the last // * Use |ParseValueAndAssignSubcomponentsByFallbackMethod()| as the last
// resort to parse |value_|. This method must produce a valid result. // resort to parse |value_|. This method must produce a valid result.
...@@ -247,8 +247,8 @@ class AddressComponent { ...@@ -247,8 +247,8 @@ class AddressComponent {
} }
// Returns the parse expressions by relevance for testing. // Returns the parse expressions by relevance for testing.
std::vector<const RE2*> GetParseExpressionsByRelevanceForTesting() { std::vector<const RE2*> GetParseRegularExpressionsByRelevanceForTesting() {
return GetParseExpressionsByRelevance(); return GetParseRegularExpressionsByRelevance();
} }
// Returns a reference to the root node of the tree for testing. // Returns a reference to the root node of the tree for testing.
...@@ -279,7 +279,7 @@ class AddressComponent { ...@@ -279,7 +279,7 @@ class AddressComponent {
// Returns pointers to regular expressions sorted by their relevance. // Returns pointers to regular expressions sorted by their relevance.
// This method is virtual and can be reimplemented for each type. // This method is virtual and can be reimplemented for each type.
virtual std::vector<const RE2*> GetParseExpressionsByRelevance() const; virtual std::vector<const RE2*> GetParseRegularExpressionsByRelevance() const;
// Method to parse |value_| into the values of |subcomponents_|. The // Method to parse |value_| into the values of |subcomponents_|. The
// purpose of this method is to cover special cases. This method returns true // purpose of this method is to cover special cases. This method returns true
...@@ -338,9 +338,9 @@ class AddressComponent { ...@@ -338,9 +338,9 @@ class AddressComponent {
const base::string16& format) const; const base::string16& format) const;
// This method uses regular expressions acquired by // This method uses regular expressions acquired by
// |GetParseExpressionsByRelevance| to parse |value_| into the values of the // |GetParseRegularExpressionsByRelevance| to parse |value_| into the values
// subcomponents. Returns true on success and is allowed to fail. // of the subcomponents. Returns true on success and is allowed to fail.
bool ParseValueAndAssignSubcomponentsByExpressions(); bool ParseValueAndAssignSubcomponentsByRegularExpressions();
// Returns the maximum number of components with assigned values on the path // Returns the maximum number of components with assigned values on the path
// from the component to a leaf node. // from the component to a leaf node.
......
...@@ -120,23 +120,21 @@ class TestCompoundNameMethodParsedAddressComponent : public AddressComponent { ...@@ -120,23 +120,21 @@ class TestCompoundNameMethodParsedAddressComponent : public AddressComponent {
// Creates a compound name for testing purposes that uses an expression to // Creates a compound name for testing purposes that uses an expression to
// parse. // parse.
class TestCompoundNameExpressionParsedAddressComponent class TestCompoundNameRegExParsedAddressComponent : public AddressComponent {
: public AddressComponent {
public: public:
TestCompoundNameExpressionParsedAddressComponent() TestCompoundNameRegExParsedAddressComponent()
: TestCompoundNameExpressionParsedAddressComponent(nullptr) { : TestCompoundNameRegExParsedAddressComponent(nullptr) {
expression1_ = expression1_ =
BuildExpressionFromPattern("(?P<NAME_FULL>(?P<NAME_MIDDLE>\\d*))"); BuildRegExFromPattern("(?P<NAME_FULL>(?P<NAME_MIDDLE>\\d*))");
expression2_ = expression2_ = BuildRegExFromPattern("(?P<NAME_FULL>(?P<NAME_LAST>.*))");
BuildExpressionFromPattern("(?P<NAME_FULL>(?P<NAME_LAST>.*))");
} }
explicit TestCompoundNameExpressionParsedAddressComponent( explicit TestCompoundNameRegExParsedAddressComponent(AddressComponent* parent)
AddressComponent* parent)
: AddressComponent(NAME_FULL, : AddressComponent(NAME_FULL,
parent, parent,
{&first_name_, &middle_name_, &last_name_}) {} {&first_name_, &middle_name_, &last_name_}) {}
std::vector<const RE2*> GetParseExpressionsByRelevance() const override { std::vector<const RE2*> GetParseRegularExpressionsByRelevance()
const override {
// The first two expressions will fail and the last one will be // The first two expressions will fail and the last one will be
// successful. // successful.
return {nullptr, expression1_.get(), expression2_.get()}; return {nullptr, expression1_.get(), expression2_.get()};
...@@ -765,8 +763,8 @@ TEST(AutofillStructuredAddressAddressComponent, ...@@ -765,8 +763,8 @@ TEST(AutofillStructuredAddressAddressComponent,
// Tests parsing using a defined method. // Tests parsing using a defined method.
TEST(AutofillStructuredAddressAddressComponent, TEST(AutofillStructuredAddressAddressComponent,
TestParseValueAndAssignSubcomponentsByExpression) { TestParseValueAndAssignSubcomponentsByRegEx) {
TestCompoundNameExpressionParsedAddressComponent compound_component; TestCompoundNameRegExParsedAddressComponent compound_component;
compound_component.SetValue(ASCIIToUTF16("Dr. Strangelove"), compound_component.SetValue(ASCIIToUTF16("Dr. Strangelove"),
VerificationStatus::kObserved); VerificationStatus::kObserved);
compound_component.ParseValueAndAssignSubcomponents(); compound_component.ParseValueAndAssignSubcomponents();
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/data_model/autofill_structured_address_constants.h"
namespace autofill {
namespace structured_address {
const char kSingleWordRe[] = "(?:\\w+)";
} // namespace structured_address
} // namespace autofill
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_CONSTANTS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_CONSTANTS_H_
namespace autofill {
namespace structured_address {
// Regular expression pattern to match a single word.
extern const char kSingleWordRe[];
} // namespace structured_address
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_CONSTANTS_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h"
#include <utility>
#include "components/autofill/core/browser/data_model/autofill_structured_address_constants.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "base/notreached.h"
namespace autofill {
namespace structured_address {
StructuredAddressesRegExProvider::StructuredAddressesRegExProvider() = default;
// static
StructuredAddressesRegExProvider* StructuredAddressesRegExProvider::Instance() {
static base::NoDestructor<StructuredAddressesRegExProvider>
g_expression_provider;
return g_expression_provider.get();
}
std::string StructuredAddressesRegExProvider::GetPattern(
RegEx expression_identifier) {
switch (expression_identifier) {
case RegEx::kSingleWord:
return kSingleWordRe;
}
NOTREACHED();
}
const RE2* StructuredAddressesRegExProvider::GetRegEx(
RegEx expression_identifier) {
base::AutoLock lock(lock_);
auto it = cached_expressions_.find(expression_identifier);
if (it == cached_expressions_.end()) {
std::unique_ptr<const RE2> expression =
BuildRegExFromPattern(GetPattern(expression_identifier));
const RE2* expresstion_ptr = expression.get();
cached_expressions_.emplace(expression_identifier, std::move(expression));
return expresstion_ptr;
}
return it->second.get();
}
} // namespace structured_address
} // namespace autofill
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_REGEX_PROVIDER_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_REGEX_PROVIDER_H_
#include <memory>
#include <string>
#include "base/containers/flat_map.h"
#include "base/no_destructor.h"
#include "base/synchronization/lock.h"
#include "third_party/re2/src/re2/re2.h"
namespace autofill {
namespace structured_address {
// Enumeration of all regular expressions supported for matching and parsing
// values in an AddressComponent tree.
enum class RegEx {
kSingleWord,
kLastRegEx = kSingleWord,
};
// This singleton class builds and caches the regular expressions for value
// parsing and characterization of values in an AddressComponent tree.
// It also builds the foundation for acquiring expressions from different
// sources.
class StructuredAddressesRegExProvider {
public:
StructuredAddressesRegExProvider& operator=(
const StructuredAddressesRegExProvider&) = delete;
StructuredAddressesRegExProvider(const StructuredAddressesRegExProvider&) =
delete;
~StructuredAddressesRegExProvider() = delete;
// Returns a singleton instance of this class.
static StructuredAddressesRegExProvider* Instance();
// Returns the regular expression corresponding to
// |expression_identifier|. If the expression is not cached yet, it is build
// by calling |BuildRegEx(expression_identifier)|. If the expression
// can't be build, nullptr is returned.
const RE2* GetRegEx(RegEx expression_identifier);
#if UNIT_TEST
bool IsCachedForTesting(RegEx expression_identifier) {
return cached_expressions_.count(expression_identifier) > 0;
}
#endif
private:
StructuredAddressesRegExProvider();
// Since the constructor is private, |base::NoDestructor| must be a friend to
// be allowed to construct the cache.
friend class base::NoDestructor<StructuredAddressesRegExProvider>;
// Fetches a pattern identified by |expression_identifier|.
// This method is virtual and is meant to be overridden by future
// implementations that utilize multiple sources for retrieving patterns.
virtual std::string GetPattern(RegEx expression_identifier);
// A map to store already compiled enumerated expressions keyed by
// |RegEx|.
base::flat_map<RegEx, std::unique_ptr<const RE2>> cached_expressions_;
// A lock to prevent concurrent access to the cached expressions map.
base::Lock lock_;
};
} // namespace structured_address
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_PATTERN_REGEX_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h"
#include "base/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
namespace structured_address {
// Tests the caching of a compiled regular expression.
TEST(AutofillStructuredAddressRegExProvider, IsRegExCached) {
auto* g_pattern_provider = StructuredAddressesRegExProvider::Instance();
EXPECT_FALSE(g_pattern_provider->IsCachedForTesting(RegEx::kSingleWord));
ASSERT_TRUE(StructuredAddressesRegExProvider::Instance()
->GetRegEx(RegEx::kSingleWord)
->ok());
EXPECT_TRUE(g_pattern_provider->IsCachedForTesting(RegEx::kSingleWord));
}
// Builds all expressions and verifes that the result is not a nullptr.
TEST(AutofillStructuredAddressRegExProvider, BuildAllRegExs) {
for (int i = 0; i <= static_cast<int>(RegEx::kLastRegEx); i++) {
auto* g_pattern_provider = StructuredAddressesRegExProvider::Instance();
EXPECT_NE(g_pattern_provider->GetRegEx(static_cast<RegEx>(i)), nullptr);
}
}
} // namespace structured_address
} // namespace autofill
...@@ -18,46 +18,46 @@ ...@@ -18,46 +18,46 @@
namespace autofill { namespace autofill {
namespace structured_address { namespace structured_address {
Re2ExpressionCache::Re2ExpressionCache() = default; Re2RegExCache::Re2RegExCache() = default;
// static // static
Re2ExpressionCache* Re2ExpressionCache::Instance() { Re2RegExCache* Re2RegExCache::Instance() {
static base::NoDestructor<Re2ExpressionCache> g_re2regex_cache; static base::NoDestructor<Re2RegExCache> g_re2regex_cache;
return g_re2regex_cache.get(); return g_re2regex_cache.get();
} }
const RE2* Re2ExpressionCache::GetExpression(const std::string& pattern) { const RE2* Re2RegExCache::GetRegEx(const std::string& pattern) {
// For thread safety, acquire a lock to prevent concurrent access. // For thread safety, acquire a lock to prevent concurrent access.
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
auto it = expression_map_.find(pattern); auto it = regex_map_.find(pattern);
if (it != expression_map_.end()) { if (it != regex_map_.end()) {
const RE2* expression = it->second.get(); const RE2* regex = it->second.get();
return expression; return regex;
} }
// Build the expression and verify it is correct. // Build the expression and verify it is correct.
auto expression_ptr = BuildExpressionFromPattern(pattern); auto regex_ptr = BuildRegExFromPattern(pattern);
// Insert the expression into the map, check the success and return the // Insert the expression into the map, check the success and return the
// pointer. // pointer.
auto result = expression_map_.emplace(pattern, std::move(expression_ptr)); auto result = regex_map_.emplace(pattern, std::move(regex_ptr));
DCHECK(result.second); DCHECK(result.second);
return result.first->second.get(); return result.first->second.get();
} }
std::unique_ptr<const RE2> BuildExpressionFromPattern(std::string pattern) { std::unique_ptr<const RE2> BuildRegExFromPattern(std::string pattern) {
RE2::Options opt; RE2::Options opt;
opt.set_case_sensitive(false); opt.set_case_sensitive(false);
auto expression = std::make_unique<const RE2>(pattern, opt); auto regex = std::make_unique<const RE2>(pattern, opt);
if (!expression->ok()) { if (!regex->ok()) {
DEBUG_ALIAS_FOR_CSTR(pattern_copy, pattern.c_str(), 128); DEBUG_ALIAS_FOR_CSTR(pattern_copy, pattern.c_str(), 128);
base::debug::DumpWithoutCrashing(); base::debug::DumpWithoutCrashing();
} }
return expression; return regex;
} }
bool ParseValueByRegularExpression( bool ParseValueByRegularExpression(
...@@ -66,22 +66,21 @@ bool ParseValueByRegularExpression( ...@@ -66,22 +66,21 @@ bool ParseValueByRegularExpression(
std::map<std::string, std::string>* result_map) { std::map<std::string, std::string>* result_map) {
DCHECK(result_map); DCHECK(result_map);
const RE2* expression = const RE2* regex = Re2RegExCache::Instance()->GetRegEx(pattern);
Re2ExpressionCache::Instance()->GetExpression(pattern);
return ParseValueByRegularExpression(value, expression, result_map); return ParseValueByRegularExpression(value, regex, result_map);
} }
bool ParseValueByRegularExpression( bool ParseValueByRegularExpression(
const std::string& value, const std::string& value,
const RE2* expression, const RE2* regex,
std::map<std::string, std::string>* result_map) { std::map<std::string, std::string>* result_map) {
if (!expression || !expression->ok()) if (!regex || !regex->ok())
return false; return false;
// Get the number of capturing groups in the expression. // Get the number of capturing groups in the expression.
// Note, the capturing group for the full match is not counted. // Note, the capturing group for the full match is not counted.
size_t number_of_capturing_groups = expression->NumberOfCapturingGroups() + 1; size_t number_of_capturing_groups = regex->NumberOfCapturingGroups() + 1;
// Create result vectors to get the matches for the capturing groups. // Create result vectors to get the matches for the capturing groups.
std::vector<std::string> results(number_of_capturing_groups); std::vector<std::string> results(number_of_capturing_groups);
...@@ -96,14 +95,14 @@ bool ParseValueByRegularExpression( ...@@ -96,14 +95,14 @@ bool ParseValueByRegularExpression(
} }
// One capturing group is not counted since it holds the full match. // One capturing group is not counted since it holds the full match.
if (!RE2::FullMatchN(value, *expression, match_results_ptr.data(), if (!RE2::FullMatchN(value, *regex, match_results_ptr.data(),
number_of_capturing_groups - 1)) number_of_capturing_groups - 1))
return false; return false;
// If successful, write the values into the results map. // If successful, write the values into the results map.
// Note, the capturing group for the full match creates an off-by-one scenario // Note, the capturing group for the full match creates an off-by-one scenario
// in the indexing. // in the indexing.
for (auto named_group : expression->NamedCapturingGroups()) for (auto named_group : regex->NamedCapturingGroups())
(*result_map)[named_group.first] = (*result_map)[named_group.first] =
std::move(results.at(named_group.second - 1)); std::move(results.at(named_group.second - 1));
...@@ -111,24 +110,22 @@ bool ParseValueByRegularExpression( ...@@ -111,24 +110,22 @@ bool ParseValueByRegularExpression(
} }
bool IsPartialMatch(const std::string& value, const std::string& pattern) { bool IsPartialMatch(const std::string& value, const std::string& pattern) {
const RE2* expression = const RE2* regex = Re2RegExCache::Instance()->GetRegEx(pattern);
Re2ExpressionCache::Instance()->GetExpression(pattern); if (!regex || !regex->ok())
if (!expression || !expression->ok())
return false; return false;
return RE2::PartialMatch(value, *expression); return RE2::PartialMatch(value, *regex);
} }
std::vector<std::string> GetAllPartialMatches(const std::string& value, std::vector<std::string> GetAllPartialMatches(const std::string& value,
const std::string& pattern) { const std::string& pattern) {
const RE2* expression = const RE2* regex = Re2RegExCache::Instance()->GetRegEx(pattern);
Re2ExpressionCache::Instance()->GetExpression(pattern); if (!regex || !regex->ok())
if (!expression || !expression->ok())
return {}; return {};
re2::StringPiece input(value); re2::StringPiece input(value);
std::string match; std::string match;
std::vector<std::string> matches; std::vector<std::string> matches;
while (re2::RE2::FindAndConsume(&input, *expression, &match)) { while (re2::RE2::FindAndConsume(&input, *regex, &match)) {
matches.emplace_back(match); matches.emplace_back(match);
} }
return matches; return matches;
......
...@@ -19,36 +19,36 @@ namespace autofill { ...@@ -19,36 +19,36 @@ namespace autofill {
namespace structured_address { namespace structured_address {
// A cache for compiled RE2 regular expressions. // A cache for compiled RE2 regular expressions.
class Re2ExpressionCache { class Re2RegExCache {
public: public:
Re2ExpressionCache& operator=(const Re2ExpressionCache&) = delete; Re2RegExCache& operator=(const Re2RegExCache&) = delete;
Re2ExpressionCache(const Re2ExpressionCache&) = delete; Re2RegExCache(const Re2RegExCache&) = delete;
~Re2ExpressionCache() = delete; ~Re2RegExCache() = delete;
// Returns a singleton instance. // Returns a singleton instance.
static Re2ExpressionCache* Instance(); static Re2RegExCache* Instance();
// Returns a pointer to a constant compiled expression that matches |pattern| // Returns a pointer to a constant compiled expression that matches |pattern|
// case-insensitively. // case-insensitively.
const RE2* GetExpression(const std::string& pattern); const RE2* GetRegEx(const std::string& pattern);
#ifdef UNIT_TEST #ifdef UNIT_TEST
// Returns true if the compiled regular expression corresponding to |pattern| // Returns true if the compiled regular expression corresponding to |pattern|
// is cached. // is cached.
bool IsExpressionCachedForTesting(const std::string& pattern) { bool IsRegExCachedForTesting(const std::string& pattern) {
return expression_map_.count(pattern) > 0; return regex_map_.count(pattern) > 0;
} }
#endif #endif
private: private:
Re2ExpressionCache(); Re2RegExCache();
// Since the constructor is private, |base::NoDestructor| must be friend to be // Since the constructor is private, |base::NoDestructor| must be friend to be
// allowed to construct the cache. // allowed to construct the cache.
friend class base::NoDestructor<Re2ExpressionCache>; friend class base::NoDestructor<Re2RegExCache>;
// Stores a compiled regular expression keyed by its corresponding |pattern|. // Stores a compiled regular expression keyed by its corresponding |pattern|.
std::map<std::string, std::unique_ptr<const RE2>> expression_map_; std::map<std::string, std::unique_ptr<const RE2>> regex_map_;
// A lock to prevent concurrent access to the map. // A lock to prevent concurrent access to the map.
base::Lock lock_; base::Lock lock_;
...@@ -67,11 +67,11 @@ bool ParseValueByRegularExpression( ...@@ -67,11 +67,11 @@ bool ParseValueByRegularExpression(
// pattern. // pattern.
bool ParseValueByRegularExpression( bool ParseValueByRegularExpression(
const std::string& value, const std::string& value,
const RE2* expression, const RE2* regex,
std::map<std::string, std::string>* result_map); std::map<std::string, std::string>* result_map);
// Returns a compiled case insensitive regular expression for |pattern|. // Returns a compiled case insensitive regular expression for |pattern|.
std::unique_ptr<const RE2> BuildExpressionFromPattern(std::string pattern); std::unique_ptr<const RE2> BuildRegExFromPattern(std::string pattern);
// Returns true if |value| can be matched with |pattern|. // Returns true if |value| can be matched with |pattern|.
bool IsPartialMatch(const std::string& value, const std::string& pattern); bool IsPartialMatch(const std::string& value, const std::string& pattern);
......
...@@ -92,14 +92,14 @@ TEST(AutofillStructuredAddressUtils, ...@@ -92,14 +92,14 @@ TEST(AutofillStructuredAddressUtils,
} }
TEST(AutofillStructuredAddressUtils, TEST(AutofillStructuredAddressUtils,
TestParseValueByRegularExpression_InvalidExpression) { TestParseValueByRegularExpression_InvalidRegEx) {
std::string regex = "(!<INVALID"; std::string regex = "(!<INVALID";
std::string value = "first middle1 middle2 middle3 last"; std::string value = "first middle1 middle2 middle3 last";
std::map<std::string, std::string> result_map; std::map<std::string, std::string> result_map;
EXPECT_FALSE(ParseValueByRegularExpression(value, regex, &result_map)); EXPECT_FALSE(ParseValueByRegularExpression(value, regex, &result_map));
auto expression = BuildExpressionFromPattern(regex); auto expression = BuildRegExFromPattern(regex);
EXPECT_FALSE( EXPECT_FALSE(
ParseValueByRegularExpression(value, expression.get(), &result_map)); ParseValueByRegularExpression(value, expression.get(), &result_map));
} }
...@@ -121,21 +121,19 @@ TEST(AutofillStructuredAddressUtils, TestIsPartialMatch) { ...@@ -121,21 +121,19 @@ TEST(AutofillStructuredAddressUtils, TestIsPartialMatch) {
} }
// Test the matching of a value against an invalid regular expression. // Test the matching of a value against an invalid regular expression.
TEST(AutofillStructuredAddressUtils, TestIsPartialMatch_InvalidExpression) { TEST(AutofillStructuredAddressUtils, TestIsPartialMatch_InvalidRegEx) {
EXPECT_FALSE(IsPartialMatch("123 sdf 123", "(!<sdf")); EXPECT_FALSE(IsPartialMatch("123 sdf 123", "(!<sdf"));
} }
// Test the caching of regular expressions. // Test the caching of regular expressions.
TEST(AutofillStructuredAddressUtils, TestExpressionCaching) { TEST(AutofillStructuredAddressUtils, TestRegExCaching) {
std::string pattern = "(?P<SOME_EXPRESSION>.)"; std::string pattern = "(?P<SOME_EXPRESSION>.)";
// Verify that the pattern is not cached yet. // Verify that the pattern is not cached yet.
EXPECT_FALSE( EXPECT_FALSE(Re2RegExCache::Instance()->IsRegExCachedForTesting(pattern));
Re2ExpressionCache::Instance()->IsExpressionCachedForTesting(pattern));
// Request the regular expression and verify that it is cached afterwards. // Request the regular expression and verify that it is cached afterwards.
Re2ExpressionCache::Instance()->GetExpression(pattern); Re2RegExCache::Instance()->GetRegEx(pattern);
EXPECT_TRUE( EXPECT_TRUE(Re2RegExCache::Instance()->IsRegExCachedForTesting(pattern));
Re2ExpressionCache::Instance()->IsExpressionCachedForTesting(pattern));
} }
TEST(AutofillStructuredAddressUtils, TestGetAllPartialMatches) { TEST(AutofillStructuredAddressUtils, TestGetAllPartialMatches) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment