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

[Autofill][SlimShady] General Hybrid Structure Component.

The CL introduces a data structure to manage address components that
must support the duality of an structured and unstructured
representation.

This is a reland with a fixed DCHECK statement.

Change-Id: I95ec6b67bb6681b1dec9c1eb951439e916e932ec
Bug: 1099202
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2307375Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Commit-Queue: Matthias Körber <koerber@google.com>
Cr-Commit-Position: refs/heads/master@{#790310}
parent 832b6e5f
...@@ -88,6 +88,8 @@ jumbo_static_library("browser") { ...@@ -88,6 +88,8 @@ jumbo_static_library("browser") {
"data_model/autofill_profile.h", "data_model/autofill_profile.h",
"data_model/autofill_profile_comparator.cc", "data_model/autofill_profile_comparator.cc",
"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.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",
...@@ -568,6 +570,7 @@ source_set("unit_tests") { ...@@ -568,6 +570,7 @@ source_set("unit_tests") {
"data_model/autofill_data_model_unittest.cc", "data_model/autofill_data_model_unittest.cc",
"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_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",
......
// 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_component.h"
#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include "base/strings/strcat.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/field_types.h"
namespace autofill {
namespace structured_address {
AddressComponent::AddressComponent(ServerFieldType storage_type)
: AddressComponent(storage_type, nullptr, {}) {}
AddressComponent::AddressComponent(ServerFieldType storage_type,
AddressComponent* parent)
: AddressComponent(storage_type, parent, {}) {}
AddressComponent::AddressComponent(ServerFieldType storage_type,
AddressComponent* parent,
std::vector<AddressComponent*> subcomponents)
: value_verification_status_(VerificationStatus::kNoStatus),
storage_type_(storage_type),
subcomponents_(subcomponents),
parent_(parent) {}
AddressComponent::~AddressComponent() = default;
ServerFieldType AddressComponent::GetStorageType() const {
return storage_type_;
}
std::string AddressComponent::GetStorageTypeName() const {
return AutofillType(storage_type_).ToString();
}
AddressComponent& AddressComponent::operator=(const AddressComponent& right) {
DCHECK(GetStorageType() == right.GetStorageType());
if (this == &right)
return *this;
value_ = right.value_;
value_verification_status_ = right.value_verification_status_;
DCHECK(right.subcomponents_.size() == subcomponents_.size());
for (size_t i = 0; i < right.subcomponents_.size(); i++)
*subcomponents_[i] = *right.subcomponents_[i];
return *this;
}
bool AddressComponent::operator==(const AddressComponent& right) const {
if (this == &right)
return true;
if (GetStorageType() != right.GetStorageType())
return false;
if (value_ != right.value_ ||
value_verification_status_ != right.value_verification_status_)
return false;
DCHECK(right.subcomponents_.size() == subcomponents_.size());
for (size_t i = 0; i < right.subcomponents_.size(); i++)
if (!(*subcomponents_[i] == *right.subcomponents_[i]))
return false;
return true;
}
bool AddressComponent::operator!=(const AddressComponent& right) const {
return !(*this == right);
}
bool AddressComponent::IsAtomic() const {
return subcomponents_.empty();
}
VerificationStatus AddressComponent::GetVerificationStatus() const {
return value_verification_status_;
}
const base::string16& AddressComponent::GetValue() const {
if (value_.has_value())
return value_.value();
return base::EmptyString16();
}
bool AddressComponent::IsValueAssigned() const {
return value_.has_value();
}
void AddressComponent::SetValue(base::string16 value,
VerificationStatus status) {
value_ = std::move(value);
value_verification_status_ = status;
}
void AddressComponent::UnsetValue() {
value_.reset();
value_verification_status_ = VerificationStatus::kNoStatus;
}
void AddressComponent::GetSupportedTypes(
ServerFieldTypeSet* supported_types) const {
// A proper AddressComponent tree contains every type only once.
DCHECK(supported_types->find(storage_type_) == supported_types->end())
<< "The AddressComponent already contains a node that supports this "
"type: "
<< storage_type_;
supported_types->insert(storage_type_);
GetAdditionalSupportedFieldTypes(supported_types);
for (auto* subcomponent : subcomponents_)
subcomponent->GetSupportedTypes(supported_types);
}
bool AddressComponent::ConvertAndSetValueForAdditionalFieldTypeName(
const std::string& field_type_name,
const base::string16& value,
const VerificationStatus& status) {
return false;
}
bool AddressComponent::ConvertAndGetTheValueForAdditionalFieldTypeName(
const std::string& field_type_name,
base::string16* value) const {
return false;
}
base::string16 AddressComponent::GetBestFormatString() const {
// If the component is atomic, the format string is just the value.
if (IsAtomic())
return base::ASCIIToUTF16(GetPlaceholderToken(GetStorageTypeName()));
// Otherwise, the canonical format string is the concatenation of all
// subcomponents by their natural order.
std::vector<std::string> format_pieces;
for (const auto* subcomponent : subcomponents_) {
std::string format_piece = GetPlaceholderToken(
AutofillType(subcomponent->GetStorageType()).ToString());
format_pieces.emplace_back(std::move(format_piece));
}
return base::ASCIIToUTF16(base::JoinString(format_pieces, " "));
}
std::vector<ServerFieldType> AddressComponent::GetSubcomponentTypes() const {
std::vector<ServerFieldType> subcomponent_types;
subcomponent_types.reserve(subcomponents_.size());
for (const auto* subcomponent : subcomponents_) {
subcomponent_types.emplace_back(subcomponent->GetStorageType());
}
return subcomponent_types;
}
bool AddressComponent::SetValueForTypeIfPossible(
const ServerFieldType& type,
const base::string16& value,
const VerificationStatus& verification_status,
bool invalidate_child_nodes,
bool invalidate_parent_nodes) {
return SetValueForTypeIfPossible(AutofillType(type).ToString(), value,
verification_status, invalidate_child_nodes,
invalidate_parent_nodes);
}
bool AddressComponent::SetValueForTypeIfPossible(
const std::string& type_name,
const base::string16& value,
const VerificationStatus& verification_status,
bool invalidate_child_nodes,
bool invalidate_parent_nodes) {
bool value_set = false;
// If the type is the storage type of the component, it can directly be
// returned.
if (type_name == GetStorageTypeName()) {
SetValue(value, verification_status);
value_set = true;
} else if (ConvertAndSetValueForAdditionalFieldTypeName(
type_name, value, verification_status)) {
// The conversion using a field type was successful.
value_set = true;
}
if (value_set) {
if (invalidate_child_nodes)
UnsetSubcomponents();
return true;
}
// Finally, probe if the type is supported by one of the subcomponents.
for (auto* subcomponent : subcomponents_) {
if (subcomponent->SetValueForTypeIfPossible(
type_name, value, verification_status, invalidate_child_nodes,
invalidate_parent_nodes)) {
if (invalidate_parent_nodes)
UnsetValue();
return true;
}
}
return false;
}
void AddressComponent::UnsetAddressComponentAndItsSubcomponents() {
UnsetValue();
UnsetSubcomponents();
}
void AddressComponent::UnsetSubcomponents() {
for (auto* component : subcomponents_)
component->UnsetAddressComponentAndItsSubcomponents();
}
bool AddressComponent::GetValueAndStatusForTypeIfPossible(
const ServerFieldType& type,
base::string16* value,
VerificationStatus* status) const {
return GetValueAndStatusForTypeIfPossible(AutofillType(type).ToString(),
value, status);
}
bool AddressComponent::GetValueAndStatusForTypeIfPossible(
const std::string& type_name,
base::string16* value,
VerificationStatus* status) const {
// If the value is the storage type, it can be simply returned.
if (type_name == GetStorageTypeName()) {
if (value)
*value = value_.value_or(base::string16());
if (status)
*status = GetVerificationStatus();
return true;
}
// Otherwise, probe if it is a supported field type that can be converted.
if (this->ConvertAndGetTheValueForAdditionalFieldTypeName(type_name, value)) {
if (status)
*status = GetVerificationStatus();
return true;
}
// Finally, try to retrieve the value from one of the subcomponents.
for (const auto* subcomponent : subcomponents_) {
if (subcomponent->GetValueAndStatusForTypeIfPossible(type_name, value,
status))
return true;
}
return false;
}
base::string16 AddressComponent::GetValueForType(
const ServerFieldType& type) const {
return GetValueForType(AutofillType(type).ToString());
}
base::string16 AddressComponent::GetValueForType(
const std::string& type_name) const {
base::string16 value;
bool success = GetValueAndStatusForTypeIfPossible(type_name, &value, nullptr);
DCHECK(success);
return value;
}
VerificationStatus AddressComponent::GetVerificationStatusForType(
const ServerFieldType& type) const {
return GetVerificationStatusForType(AutofillType(type).ToString());
}
VerificationStatus AddressComponent::GetVerificationStatusForType(
const std::string& type_name) const {
VerificationStatus status = VerificationStatus::kNoStatus;
bool success =
GetValueAndStatusForTypeIfPossible(type_name, nullptr, &status);
DCHECK(success);
return status;
}
bool AddressComponent::UnsetValueForTypeIfSupported(
const ServerFieldType& type) {
if (type == storage_type_) {
UnsetAddressComponentAndItsSubcomponents();
return true;
}
for (auto* subcomponent : subcomponents_) {
if (subcomponent->UnsetValueForTypeIfSupported(type))
return true;
}
return false;
}
bool AddressComponent::ParseValueAndAssignSubcomponentsByMethod() {
return false;
}
std::vector<const RE2*> AddressComponent::GetParseExpressionsByRelevance()
const {
return {};
}
void AddressComponent::ParseValueAndAssignSubcomponents() {
// Set the values of all subcomponents to the empty string and set the
// verification status to kParsed.
for (auto* subcomponent : subcomponents_)
subcomponent->SetValue(base::string16(), VerificationStatus::kParsed);
// First attempt, try to parse by method.
if (ParseValueAndAssignSubcomponentsByMethod())
return;
// Second attempt, try to parse by expressions.
if (ParseValueAndAssignSubcomponentsByExpressions())
return;
// As a final fallback, parse using the fallback method.
ParseValueAndAssignSubcomponentsByFallbackMethod();
}
bool AddressComponent::ParseValueAndAssignSubcomponentsByExpressions() {
for (const auto* parse_expression : GetParseExpressionsByRelevance()) {
if (!parse_expression)
continue;
std::map<std::string, std::string> result_map;
if (ParseValueByRegularExpression(base::UTF16ToUTF8(GetValue()),
parse_expression, &result_map)) {
// Parsing was successful and results from the result map can be written
// to the structure.
for (const auto& result_entry : result_map) {
std::string field_type = result_entry.first;
base::string16 field_value = base::UTF8ToUTF16(result_entry.second);
bool success = SetValueForTypeIfPossible(field_type, field_value,
VerificationStatus::kParsed);
// Setting the value should always work unless the regular expression is
// invalid.
DCHECK(success);
}
return true;
}
}
return false;
}
void AddressComponent::ParseValueAndAssignSubcomponentsByFallbackMethod() {
// There is nothing to do for an atomic component.
if (IsAtomic())
return;
// An empty string is trivially parsable.
if (GetValue().empty())
return;
// Split the string by spaces.
std::vector<base::string16> space_separated_tokens =
base::SplitString(GetValue(), base::UTF8ToUTF16(" "),
base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
auto token_iterator = space_separated_tokens.begin();
auto subcomponent_types = GetSubcomponentTypes();
// Assign one space-separated token each to all but the last subcomponent.
for (size_t i = 0; (i + 1) < subcomponent_types.size(); i++) {
// If there are no tokens left, parsing is done.
if (token_iterator == space_separated_tokens.end())
return;
// Set the current token to the type and advance the token iterator.
bool success = SetValueForTypeIfPossible(
subcomponent_types[i], *token_iterator, VerificationStatus::kParsed);
// By design, setting the value should never fail.
DCHECK(success);
token_iterator++;
}
// Collect all remaining tokens in the last subcomponent.
base::string16 remaining_tokens = base::JoinString(
std::vector<base::string16>(token_iterator, space_separated_tokens.end()),
base::ASCIIToUTF16(" "));
// By design, it should be possible to assign the value unless the regular
// expression is wrong.
bool success = SetValueForTypeIfPossible(
subcomponent_types.back(), remaining_tokens, VerificationStatus::kParsed);
DCHECK(success);
}
void AddressComponent::FormatValueFromSubcomponents() {
// Get the most suited format string.
base::string16 format_string = GetBestFormatString();
// Perform the following steps on a copy of the format string.
// * Replace all the placeholders of the form ${TYPE_NAME} with the
// corresponding value.
// * Strip away double spaces as they may occur after replacing a placeholder
// with an empty value.
base::string16 result = ReplacePlaceholderTypesWithValues(format_string);
result = base::CollapseWhitespace(result, /*trim_line_breaks=*/false);
SetValue(result, VerificationStatus::kFormatted);
}
base::string16 AddressComponent::ReplacePlaceholderTypesWithValues(
const base::string16& format) const {
// Replaces placeholders using the following rules.
// Assumptions: Placeholder values are not nested.
//
// * Search for a substring of the form "{$[^}]*}".
//
// * Check if this substring is a supported type of this component.
//
// * If yes, replace the substring with the corresponding value.
//
// * If the corresponding value is empty, return false.
auto control_parmater = base::ASCIIToUTF16("$").at(0);
auto control_parmater_open_delimitor = base::ASCIIToUTF16("{").at(0);
auto control_parmater_close_delimitor = base::ASCIIToUTF16("}").at(0);
// Create a result vector for the tokens that are joined in the end.
std::vector<base::StringPiece16> result_pieces;
// Reserve space for 10 tokens. This should be sufficient for most cases.
result_pieces.reserve(10);
// Store the inserted values to allow the used StringPieces to stay valid.
std::vector<const base::string16> inserted_values;
inserted_values.reserve(4);
// Use a StringPiece rather than the string since this allows for getting
// cheap views onto substrings.
const base::StringPiece16 format_piece = format;
bool started_control_sequence = false;
// Track until which index the format string was fully processed.
size_t processed_until_index = 0;
for (size_t i = 0; i < format_piece.size(); ++i) {
// Check if a control sequence is started by '${'
if (format_piece[i] == control_parmater && i < format_piece.size() - 1 &&
format_piece[i + 1] == control_parmater_open_delimitor) {
// A control sequence is started.
started_control_sequence = true;
// Append the preceding string since it can't be a valid placeholder.
if (i > 0) {
result_pieces.emplace_back(format_piece.substr(
processed_until_index, i - processed_until_index));
}
processed_until_index = i;
++i;
} else if (started_control_sequence &&
format_piece[i] == control_parmater_close_delimitor) {
// The control sequence came to an end.
started_control_sequence = false;
size_t placeholder_start = processed_until_index + 2;
base::string16 type_name =
format_piece.substr(placeholder_start, i - placeholder_start)
.as_string();
base::string16 value;
if (GetValueAndStatusForTypeIfPossible(base::UTF16ToASCII(type_name),
&value, nullptr)) {
// The type is valid and should be substituted.
inserted_values.emplace_back(std::move(value));
result_pieces.emplace_back(base::StringPiece16(inserted_values.back()));
} else {
// Append the control sequence as it is, because the type is not
// supported by the component tree.
result_pieces.emplace_back(format_piece.substr(
processed_until_index, i - processed_until_index + 1));
}
processed_until_index = i + 1;
}
}
// Append the rest of the string.
result_pieces.emplace_back(
format_piece.substr(processed_until_index, base::string16::npos));
// Build the final result.
return base::JoinString(result_pieces, base::ASCIIToUTF16(""));
}
bool AddressComponent::CompleteFullTree() {
if (!GetRootNode().IsTreeCompletable())
return false;
GetRootNode().RecursivelyCompleteTree();
return true;
}
void AddressComponent::RecursivelyCompleteTree() {
if (IsAtomic())
return;
// If the value is assigned, parse the subcomponents from the value.
if (IsValueAssigned())
ParseValueAndAssignSubcomponents();
// First call completion on all subcomponents.
for (auto* subcomponent : subcomponents_)
subcomponent->RecursivelyCompleteTree();
// Finally format the value from the sucomponents if it is not already
// assigned.
if (!IsValueAssigned())
FormatValueFromSubcomponents();
}
int AddressComponent::
MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() const {
int result = 0;
for (auto* subcomponent : subcomponents_) {
result = std::max(
result,
subcomponent
->MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths());
}
if (IsValueAssigned())
++result;
return result;
}
bool AddressComponent::IsTreeCompletable() {
return MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() == 1;
}
const AddressComponent& AddressComponent::GetRootNode() const {
if (!parent_)
return *this;
return parent_->GetRootNode();
}
AddressComponent& AddressComponent::GetRootNode() {
return const_cast<AddressComponent&>(
const_cast<const AddressComponent*>(this)->GetRootNode());
}
void AddressComponent::RecursivelyUnsetParsedAndFormattedValues() {
if (IsValueAssigned() &&
(GetVerificationStatus() == VerificationStatus::kFormatted ||
GetVerificationStatus() == VerificationStatus::kParsed))
UnsetValue();
for (auto* component : subcomponents_)
component->RecursivelyUnsetParsedAndFormattedValues();
}
void AddressComponent::UnsetParsedAndFormattedValuesInEntireTree() {
GetRootNode().RecursivelyUnsetParsedAndFormattedValues();
}
} // 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_COMPONENT_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_COMPONENT_H_
#include <map>
#include <string>
#include <vector>
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/field_types.h"
#include "third_party/re2/src/re2/re2.h"
namespace autofill {
namespace structured_address {
enum class VerificationStatus {
// No verification status assigned.
kNoStatus,
// The user used the autofill settings to verify and store this token.
kUserVerified,
// The value was observed in a form transmission.
kObserved,
// Value was built from its subcomponents.
kFormatted,
// The value token was parsed from a parent token.
kParsed,
};
// An AddressComponent is a tree structure that represents a semi-structured
// address token. Such an address token can either be an atomic leaf node or
// have a set of children, each representing a more granular subtoken of the
// component.
//
// An AddressComponent has a string representation stored in |value_| and a
// VerificationStatus stored in |verification_status_|.
// The latter indicates if the value was user-verified, observed in a form
// submission event, parsed from its parent component or was formatted from its
// child components.
//
// In a proper component tree, each AddressComponent has a unique
// ServerFieldType. Additionally, an AddressComponent may be associated with a
// list of additional field types that allow for retrieving and setting the
// Component's value in specific formats. For example, NAME_MIDDLE may be the
// storage type and NAME_MIDDLE_INITIAL is an additional field type.
//
// The usage pattern of such an address tree is as follows:
//
// * Create a tree from an observed form submission or a profile editing or
// creation event in the Chrome settings. It is assumed that the created
// tree does not have values for competing field types. Two types are competing
// iff they are on a common root-to-leaf path. For example, an imported profile
// with a value for NAME_FULL and NAME_LAST has conflicting types that
// carry redundant information.
//
// * After the creation of the tree, the values of unassigned nodes in the tree
// are deducted from the values of assigned nodes. This happens by parsing
// (taking a string and splitting it into components) or by formatting (taking
// one or multiple strings and combining them into one string).
//
// * After the completion, there should be no need to modify the tree.
//
// * A tree may be mergeable with another tree of the same type. This
// operation incorporates complementing observations. For example, in the first
// tree NAME_FIRST, NAME_MIDDLE and NAME_LAST may be parsed from an observed
// unstructured name (NAME_FULL). The second tree may be built from observing
// the structured name, and contain observed NAME_FIRST, NAME_MIDDLE and
// NAME_LAST values but only a formatted NAME_FULL value.
class AddressComponent {
public:
// Constructor for an atomic root node.
explicit AddressComponent(ServerFieldType storage_type);
// Constructor for an atomic leaf node.
explicit AddressComponent(ServerFieldType storage_type,
AddressComponent* parent);
// Constructor for a compound child node.
AddressComponent(ServerFieldType storage_type,
AddressComponent* parent,
std::vector<AddressComponent*> subcomponents);
// Disallows copies since they are not needed in the current Autofill design.
AddressComponent(const AddressComponent& other) = delete;
virtual ~AddressComponent();
// Assignment operator that works recursively down the tree and assigns the
// |value_| and |verification_status_| of every node in right to the
// corresponding nodes in |this|. For an assignment it is required that both
// nodes have the same |storage_type_|.
AddressComponent& operator=(const AddressComponent& right);
// Comparison operator that works recursively down the tree.
bool operator==(const AddressComponent& right) const;
// Inequality operator that works recursively down the tree.
bool operator!=(const AddressComponent& right) const;
// Returns the autofill storage type stored in |storage_type_|.
ServerFieldType GetStorageType() const;
// Returns the string representation of |storage_type_|.
std::string GetStorageTypeName() const;
// Returns the value verification status of the component's value;
VerificationStatus GetVerificationStatus() const;
// Returns true if the component has no subcomponents.
bool IsAtomic() const;
// Returns a constant reference to |value_.value()|. If the value is not
// assigned, an empty string is returned.
const base::string16& GetValue() const;
// Returns true if the value of this AddressComponent is assigned.
bool IsValueAssigned() const;
// Sets the value corresponding to the storage type of this AddressComponent.
void SetValue(base::string16 value, VerificationStatus status);
// Sets the value to an empty string, marks it unassigned and sets the
// verification status to |kNoStatus|.
void UnsetValue();
// The method sets the value of the current node if its |storage_type_| is
// |type| or if |ConvertAndGetTheValueForAdditionalFieldTypeName()| supports
// retrieving |type|. Otherwise, the call is delegated recursively to the
// node's children.
// Returns true if the |value_| and |verification_status_| were successfully
// set for this or an ancestor node with the storage type |type|. If
// |invalidate_child_nodes|, all child nodes of the assigned node are
// unassigned. If |invalidate_parent_nodes|, all ancestor nodes of the
// assigned node as unassigned.
bool SetValueForTypeIfPossible(const ServerFieldType& type,
const base::string16& value,
const VerificationStatus& verification_status,
bool invalidate_child_nodes = false,
bool invalidate_parent_nodes = false);
// Same as |SetValueForTypeIfPossible()| but the type is supplied in the
// corresponding string representation.
bool SetValueForTypeIfPossible(const std::string& type_name,
const base::string16& value,
const VerificationStatus& verification_status,
bool invalidate_child_nodes = false,
bool invalidate_parent_nodes = false);
// Convenience method to get the value of |type|.
// Returns an empty string if |type| is not supported.
base::string16 GetValueForType(const ServerFieldType& type) const;
// Convenience method to get the value of |type| identified by its string
// representation name. Returns an empty string if |type| is not supported.
base::string16 GetValueForType(const std::string& type) const;
// Convenience method to get the verification status of |type|.
// Returns |VerificationStatus::kNoStatus| if |type| is not supported.
VerificationStatus GetVerificationStatusForType(
const ServerFieldType& type) const;
// Convenience method to get the verification status of |type| identified by
// its name. Returns |VerificationStatus::kNoStatus| if |type| is not
// supported.
VerificationStatus GetVerificationStatusForType(
const std::string& type) const;
// Get the value and status of a |type|,
// Returns false if the |type| is not supported by the structure.
// The method returns |value_| and |validation_status_| of the current node if
// its |storage_type_| is |type| or if
// |ConvertAndSetTheValueForAdditionalFieldTypeName()| supports setting
// |type|. Otherwise, the call is delegated recursively to the node's
// children. Returns false if the neither the node or one of its ancestors
// supports |type|.
bool GetValueAndStatusForTypeIfPossible(const ServerFieldType& type,
base::string16* value,
VerificationStatus* status) const;
// Get the value and status of a |type| identified by its name.
// Returns false if the |type| is not supported by the structure.
bool GetValueAndStatusForTypeIfPossible(const std::string& type_name,
base::string16* value,
VerificationStatus* status) const;
// Returns true if the |value| and |verification_status| were successfully
// unset for |type|.
bool UnsetValueForTypeIfSupported(const ServerFieldType& type);
// Parses |value_| to assign values to the subcomponents.
// The method uses 3 stages:
//
// * Use |ParseValueAndAssignSubcomponentsByMethod()|. This stage exists
// to catch special cases and may fail. The method is virtual and can be
// implemented on the type level.
//
// * Use |ParseValueAndAssignSubcomponentsByExpressions()|. This stage uses a
// list of regular expressions acquired by the virtual method
// |GetParseExpressionsByRelevance()|. This stage my fail.
//
// * Use |ParseValueAndAssignSubcomponentsByFallbackMethod()| as the last
// resort to parse |value_|. This method must produce a valid result.
void ParseValueAndAssignSubcomponents();
// This methods populated the unassigned entries in the subtree of this node
// by either parsing unknown values for subcomponents from their parents, or
// vice versa, formatting unknown values from known subcomponents. The method
// is virtual and can be reimplemented on the type level.
virtual void RecursivelyCompleteTree();
// Completes the full tree by calling |RecursivelyCompleteTree()| starting
// form the root node. Returns true if the completion was successful.
bool CompleteFullTree();
// Checks if a tree is completable in the sense that there are no conflicting
// observed or verified types. This means that there is not more than one
// observed or verified node on any root-to-leaf path in the tree.
bool IsTreeCompletable();
// Recursively adds the supported types to the set. Calls
// |GetAdditionalSupportedFieldTypes()| to add field types.
void GetSupportedTypes(ServerFieldTypeSet* supported_types) const;
// Adds the additional supported field types to |supported_types|.
// The method should DCHECK that the added types are not part of the set yet.
virtual void GetAdditionalSupportedFieldTypes(
ServerFieldTypeSet* supported_types) const {}
// Unassigns all nodes with parsed or formatted values.
void UnsetParsedAndFormattedValuesInEntireTree();
// Unassigns all nodes with parsed or formatted values.
void RecursivelyUnsetParsedAndFormattedValues();
#ifdef UNIT_TEST
// Initiates the formatting of the values from the subcomponents.
void FormatValueFromSubcomponentsForTesting() {
FormatValueFromSubcomponents();
}
// Returns the best format string for testing.
base::string16 GetBestFormatStringForTesting() {
return GetBestFormatString();
}
// Returns the parse expressions by relevance for testing.
std::vector<const RE2*> GetParseExpressionsByRelevanceForTesting() {
return GetParseExpressionsByRelevance();
}
// Returns a reference to the root node of the tree for testing.
AddressComponent& GetRootNodeForTesting() { return GetRootNode(); }
// Replaces placeholder values in the best format string with the
// corresponding values.
base::string16 GetReplacedPlaceholderTypesWithValuesForTesting() const {
return ReplacePlaceholderTypesWithValues(GetBestFormatString());
}
// Returns a vector containing the |storage_types_| of all direct
// subcomponents.
std::vector<ServerFieldType> GetSubcomponentTypesForTesting() const {
return GetSubcomponentTypes();
}
#endif
protected:
// Returns a vector containing the |storage_types_| of all direct
// subcomponents.
std::vector<ServerFieldType> GetSubcomponentTypes() const;
// Heuristic method to get the best suited format string.
// This method is virtual and can be reimplemented for each type.
virtual base::string16 GetBestFormatString() const;
// Returns pointers to regular expressions sorted by their relevance.
// This method is virtual and can be reimplemented for each type.
virtual std::vector<const RE2*> GetParseExpressionsByRelevance() const;
// Method to parse |value_| into the values of |subcomponents_|. The
// purpose of this method is to cover special cases. This method returns true
// on success and is allowed to fail. On failure, the |subcomponents_| are not
// altered.
virtual bool ParseValueAndAssignSubcomponentsByMethod();
// This method parses |value_| to assign values to the subcomponents.
// The method is virtual and can be reimplemented per type.
// It must succeed.
virtual void ParseValueAndAssignSubcomponentsByFallbackMethod();
// This method is used to set the value given by a type different than the
// storage type. It must implement the conversion logic specific to each type.
// It returns true if conversion logic exists and the type can be set.
virtual bool ConvertAndSetValueForAdditionalFieldTypeName(
const std::string& field_type_name,
const base::string16& value,
const VerificationStatus& status);
// This method is used to retrieve the value for a supported field type
// different from the storage type. It must implement the conversion logic
// specific to each type. It returns true if the type is supported and the
// value can be written back to value.
// The method must handle |nullptr|s for both the value and status.
virtual bool ConvertAndGetTheValueForAdditionalFieldTypeName(
const std::string& field_type_name,
base::string16* value) const;
// Clears all parsed and formatted values.
void ClearAllParsedAndFormattedValues();
private:
// Returns a reference to the constant root node of the tree.
const AddressComponent& GetRootNode() const;
// Returns a reference to the root node of the tree.
AddressComponent& GetRootNode();
// Unsets the node and all of its children.
void UnsetAddressComponentAndItsSubcomponents();
// Unsets the children of a node.
void UnsetSubcomponents();
// Determines the |value_| from the values of the subcomponents by using the
// most suitable format string determined by |GetBestFormatString()|.
void FormatValueFromSubcomponents();
// Replaces placeholder values with the corresponding values.
base::string16 ReplacePlaceholderTypesWithValues(
const base::string16& format) const;
// Replaces placeholder values with the corresponding values.
base::string16 ReplacePlaceholderTypesWithValuesRegexVersion(
const base::string16& format) const;
// This method uses regular expressions acquired by
// |GetParseExpressionsByRelevance| to parse |value_| into the values of the
// subcomponents. Returns true on success and is allowed to fail.
bool ParseValueAndAssignSubcomponentsByExpressions();
// Returns the maximum number of components with assigned values on the path
// from the component to a leaf node.
int MaximumNumberOfAssignedAddressComponentsOnNodeToLeafPaths() const;
// The unstructured value of this component.
base::Optional<base::string16> value_;
// The verification status of |value_| indicates the certainty of the value
// to be correct.
VerificationStatus value_verification_status_;
// The storable Autofill type of the component.
const ServerFieldType storage_type_;
// A vector of pointers to the subcomponents.
std::vector<AddressComponent*> subcomponents_;
// A pointer to the parent node. It is set to nullptr if the node is the root
// node of the AddressComponent tree.
AddressComponent* const parent_;
};
} // namespace structured_address
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_STRUCTURED_ADDRESS_COMPONENT_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_component.h"
#include <stddef.h>
#include <map>
#include <string>
#include <vector>
#include "base/strings/utf_string_conversions.h"
#include "base/test/gtest_util.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
namespace autofill {
namespace structured_address {
// Creates an atomic name component for testing purposes.
class TestAtomicFirstNameAddressComponent : public AddressComponent {
public:
TestAtomicFirstNameAddressComponent()
: TestAtomicFirstNameAddressComponent(nullptr) {}
explicit TestAtomicFirstNameAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_FIRST, parent) {}
};
class TestAtomicMiddleNameAddressComponent : public AddressComponent {
public:
TestAtomicMiddleNameAddressComponent()
: TestAtomicMiddleNameAddressComponent(nullptr) {}
explicit TestAtomicMiddleNameAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_MIDDLE, parent) {}
void GetAdditionalSupportedFieldTypes(
ServerFieldTypeSet* supported_types) const override {
DCHECK(supported_types->find(NAME_MIDDLE_INITIAL) ==
supported_types->end());
supported_types->insert(NAME_MIDDLE_INITIAL);
}
bool ConvertAndSetValueForAdditionalFieldTypeName(
const std::string& field_type_name,
const base::string16& value,
const VerificationStatus& status) override {
if (field_type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
SetValue(value, status);
return true;
}
return false;
}
bool ConvertAndGetTheValueForAdditionalFieldTypeName(
const std::string& field_type_name,
base::string16* value) const override {
if (field_type_name == AutofillType(NAME_MIDDLE_INITIAL).ToString()) {
if (value) {
*value = GetValue().substr(0, 1);
}
return true;
}
return false;
}
};
class TestAtomicLastNameAddressComponent : public AddressComponent {
public:
TestAtomicLastNameAddressComponent()
: TestAtomicLastNameAddressComponent(nullptr) {}
explicit TestAtomicLastNameAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_LAST, parent) {}
};
// Creates a compound name for testing purposes.
class TestCompoundNameAddressComponent : public AddressComponent {
public:
TestCompoundNameAddressComponent()
: TestCompoundNameAddressComponent(nullptr) {}
explicit TestCompoundNameAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
{&first_name_, &middle_name_, &last_name_}) {}
AddressComponent* GetFirstNameSubComponentForTesting() {
return &first_name_;
}
private:
TestAtomicFirstNameAddressComponent first_name_{this};
TestAtomicMiddleNameAddressComponent middle_name_{this};
TestAtomicLastNameAddressComponent last_name_{this};
};
// Creates a compound name for testing purposes that uses a method for parsing.
class TestCompoundNameMethodParsedAddressComponent : public AddressComponent {
public:
TestCompoundNameMethodParsedAddressComponent()
: TestCompoundNameMethodParsedAddressComponent(nullptr) {}
explicit TestCompoundNameMethodParsedAddressComponent(
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
{&first_name_, &middle_name_, &last_name_}) {}
bool ParseValueAndAssignSubcomponentsByMethod() override {
// Assigns everything to the first name.
first_name_.SetValue(GetValue(), VerificationStatus::kParsed);
return true;
}
private:
TestAtomicFirstNameAddressComponent first_name_{this};
TestAtomicMiddleNameAddressComponent middle_name_{this};
TestAtomicLastNameAddressComponent last_name_{this};
};
// Creates a compound name for testing purposes that uses an expression to
// parse.
class TestCompoundNameExpressionParsedAddressComponent
: public AddressComponent {
public:
TestCompoundNameExpressionParsedAddressComponent()
: TestCompoundNameExpressionParsedAddressComponent(nullptr) {
expression1_ =
BuildExpressionFromPattern("(?P<NAME_FULL>(?P<NAME_MIDDLE>\\d*))");
expression2_ =
BuildExpressionFromPattern("(?P<NAME_FULL>(?P<NAME_LAST>.*))");
}
explicit TestCompoundNameExpressionParsedAddressComponent(
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
{&first_name_, &middle_name_, &last_name_}) {}
std::vector<const RE2*> GetParseExpressionsByRelevance() const override {
// The first two expressions will fail and the last one will be
// successful.
return {nullptr, expression1_.get(), expression2_.get()};
}
private:
std::unique_ptr<const RE2> expression1_;
std::unique_ptr<const RE2> expression2_;
TestAtomicFirstNameAddressComponent first_name_{this};
TestAtomicMiddleNameAddressComponent middle_name_{this};
TestAtomicLastNameAddressComponent last_name_{this};
};
// Creates a compound name with a custom format for testing purposes.
class TestCompoundNameCustomFormatAddressComponent : public AddressComponent {
public:
TestCompoundNameCustomFormatAddressComponent()
: TestCompoundNameCustomFormatAddressComponent(nullptr) {}
explicit TestCompoundNameCustomFormatAddressComponent(
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
{&first_name, &middle_name, &last_name}) {}
// Introduces a custom format with a leading last name.
base::string16 GetBestFormatString() const override {
return base::ASCIIToUTF16("${NAME_LAST}, ${NAME_FIRST}");
}
private:
TestAtomicFirstNameAddressComponent first_name{this};
TestAtomicMiddleNameAddressComponent middle_name{this};
TestAtomicLastNameAddressComponent last_name{this};
};
// Creates a compound name with a custom format with unsupported token.
class TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent
: public AddressComponent {
public:
TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent()
: TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent(
nullptr) {}
explicit TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent(
AddressComponent* parent)
: AddressComponent(NAME_FULL,
parent,
{&first_name, &middle_name, &last_name}) {}
// Introduce a custom format with a leading last name.
base::string16 GetBestFormatString() const override {
return base::ASCIIToUTF16("${NAME_LAST}, ${NAME_FIRST} ${NOT_SUPPORTED}");
}
private:
TestAtomicFirstNameAddressComponent first_name{this};
TestAtomicMiddleNameAddressComponent middle_name{this};
TestAtomicLastNameAddressComponent last_name{this};
};
class TestAtomicTitleAddressComponent : public AddressComponent {
public:
TestAtomicTitleAddressComponent()
: TestAtomicTitleAddressComponent(nullptr) {}
explicit TestAtomicTitleAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_HONORIFIC_PREFIX, parent) {}
};
// Creates a fictional compound component with sub- and sub subcomponents.
class TestCompoundNameWithTitleAddressComponent : public AddressComponent {
public:
TestCompoundNameWithTitleAddressComponent()
: TestCompoundNameWithTitleAddressComponent(nullptr) {}
explicit TestCompoundNameWithTitleAddressComponent(AddressComponent* parent)
: AddressComponent(CREDIT_CARD_NAME_FULL, parent, {&title, &full_name}) {}
private:
TestAtomicTitleAddressComponent title{this};
TestCompoundNameAddressComponent full_name{this};
};
// Creates a tree that is not proper in the sense that it contains the same type
// multiple times.
class TestNonProperFirstNameAddressComponent : public AddressComponent {
public:
TestNonProperFirstNameAddressComponent()
: TestNonProperFirstNameAddressComponent(nullptr) {}
explicit TestNonProperFirstNameAddressComponent(AddressComponent* parent)
: AddressComponent(NAME_FIRST, parent, {&second_name_first_node_}) {}
private:
TestAtomicFirstNameAddressComponent second_name_first_node_;
};
// Tests that the destructor does not crash
TEST(AutofillStructuredAddressAddressComponent, ConstructAndDestruct) {
AddressComponent* component = new AddressComponent(NAME_FULL, nullptr);
delete component;
EXPECT_TRUE(true);
}
// Tests that a non-proper AddressComponent tree fails a DCHECK for
// |GetSupportedTypes()|.
TEST(AutofillStructuredAddressAddressComponent,
TestNonProperTreeDcheckFailure) {
TestNonProperFirstNameAddressComponent non_proper_compound;
ServerFieldTypeSet supported_tpyes;
EXPECT_DCHECK_DEATH(non_proper_compound.GetSupportedTypes(&supported_tpyes));
}
// Tests getting the root node.
TEST(AutofillStructuredAddressAddressComponent, TestGetRootNode) {
TestCompoundNameAddressComponent compound_component;
// The root node should return the root node.
EXPECT_EQ(&compound_component, &(compound_component.GetRootNodeForTesting()));
// Get a pointer to a subcomponent, verify that it is not the root node and
// check that it successfully retrieves the root node.
AddressComponent* first_name_subcomponent_ptr =
compound_component.GetFirstNameSubComponentForTesting();
EXPECT_NE(&compound_component, first_name_subcomponent_ptr);
EXPECT_EQ(&compound_component,
&(first_name_subcomponent_ptr->GetRootNodeForTesting()));
}
// Tests that additional field types are correctly retrieved.
TEST(AutofillStructuredAddressAddressComponent, TestGetSupportedFieldType) {
ServerFieldTypeSet field_type_set;
TestAtomicFirstNameAddressComponent first_name_component;
TestAtomicMiddleNameAddressComponent middle_name_component;
// The first name does not have an additional supported field type.
first_name_component.GetAdditionalSupportedFieldTypes(&field_type_set);
EXPECT_EQ(field_type_set, ServerFieldTypeSet({}));
// The middle name supports an iniital.
middle_name_component.GetAdditionalSupportedFieldTypes(&field_type_set);
EXPECT_EQ(field_type_set, ServerFieldTypeSet({NAME_MIDDLE_INITIAL}));
}
// Tests setting an additional field type.
TEST(AutofillStructuredAddressAddressComponent, TestSetFieldTypeValue) {
TestCompoundNameAddressComponent compound_name;
EXPECT_TRUE(compound_name.SetValueForTypeIfPossible(
NAME_MIDDLE_INITIAL, base::UTF8ToUTF16("M"),
VerificationStatus::kObserved));
EXPECT_EQ(compound_name.GetValueForType(NAME_MIDDLE), base::UTF8ToUTF16("M"));
}
// Tests retrieving an additional field type.
TEST(AutofillStructuredAddressAddressComponent, TestGetFieldTypeValue) {
TestCompoundNameAddressComponent compound_name;
EXPECT_TRUE(compound_name.SetValueForTypeIfPossible(
NAME_MIDDLE, base::UTF8ToUTF16("Middle"), VerificationStatus::kObserved));
EXPECT_EQ(compound_name.GetValueForType(NAME_MIDDLE_INITIAL),
base::UTF8ToUTF16("M"));
EXPECT_EQ(compound_name.GetVerificationStatusForType(NAME_MIDDLE_INITIAL),
VerificationStatus::kObserved);
}
// Tests adding all supported types to the set.
TEST(AutofillStructuredAddressAddressComponent, TestGetSupportedTypes) {
ServerFieldTypeSet field_type_set;
TestAtomicFirstNameAddressComponent first_name_component;
TestAtomicMiddleNameAddressComponent middle_name_component;
TestCompoundNameAddressComponent compound_name;
// The first name only supports NAME_FIRST.
first_name_component.GetSupportedTypes(&field_type_set);
EXPECT_EQ(field_type_set, ServerFieldTypeSet({NAME_FIRST}));
// The middle name supports an initial.
field_type_set.clear();
middle_name_component.GetSupportedTypes(&field_type_set);
EXPECT_EQ(field_type_set,
ServerFieldTypeSet({NAME_MIDDLE, NAME_MIDDLE_INITIAL}));
// Verify that all types are added correctly in a compound structure.
field_type_set.clear();
compound_name.GetSupportedTypes(&field_type_set);
EXPECT_EQ(field_type_set,
ServerFieldTypeSet({NAME_MIDDLE, NAME_MIDDLE_INITIAL, NAME_FIRST,
NAME_LAST, NAME_FULL}));
}
// Tests the comparison of thw atoms of the same type.
TEST(AutofillStructuredAddressAddressComponent, TestComparisonOperator_Atom) {
AddressComponent left(NAME_FIRST);
AddressComponent right(NAME_FIRST);
left.SetValue(base::UTF8ToUTF16("some value"), VerificationStatus::kParsed);
right.SetValue(base::UTF8ToUTF16("some other value"),
VerificationStatus::kFormatted);
EXPECT_NE(left.GetValue(), right.GetValue());
EXPECT_NE(left.GetVerificationStatus(), right.GetVerificationStatus());
EXPECT_FALSE(left == right);
EXPECT_TRUE(left != right);
right.SetValue(base::UTF8ToUTF16("some value"), VerificationStatus::kParsed);
EXPECT_TRUE(left == right);
EXPECT_FALSE(left != right);
}
// Tests comparison of two different types.
TEST(AutofillStructuredAddressAddressComponent,
TestComparisonOperator_DifferentTypes) {
AddressComponent type_a1(NAME_FIRST);
AddressComponent type_a2(NAME_FIRST);
AddressComponent type_b(NAME_LAST);
EXPECT_TRUE(type_a1 == type_a2);
EXPECT_FALSE(type_a1 == type_b);
}
// Tests the comparison with itself.
TEST(AutofillStructuredAddressAddressComponent,
TestComparisonOperator_SelfComparison) {
AddressComponent type_a(NAME_FIRST);
EXPECT_TRUE(type_a == type_a);
}
// Tests the comparison operator.
TEST(AutofillStructuredAddressAddressComponent,
TestComparisonOperator_Compound) {
TestCompoundNameAddressComponent left;
TestCompoundNameAddressComponent right;
// Set left to a value and verify its state.
left.SetValueForTypeIfPossible(NAME_FULL,
base::UTF8ToUTF16("First Middle Last"),
VerificationStatus::kObserved);
EXPECT_TRUE(left.CompleteFullTree());
EXPECT_EQ(left.GetValueForType(NAME_FULL),
base::UTF8ToUTF16("First Middle Last"));
EXPECT_EQ(left.GetValueForType(NAME_FIRST), base::UTF8ToUTF16("First"));
EXPECT_EQ(left.GetValueForType(NAME_MIDDLE), base::UTF8ToUTF16("Middle"));
EXPECT_EQ(left.GetValueForType(NAME_LAST), base::UTF8ToUTF16("Last"));
EXPECT_EQ(left.GetVerificationStatusForType(NAME_FULL),
VerificationStatus::kObserved);
EXPECT_EQ(left.GetVerificationStatusForType(NAME_FIRST),
VerificationStatus::kParsed);
EXPECT_EQ(left.GetVerificationStatusForType(NAME_LAST),
VerificationStatus::kParsed);
EXPECT_EQ(left.GetVerificationStatusForType(NAME_MIDDLE),
VerificationStatus::kParsed);
// Set right to another value and verify its state.
right.SetValueForTypeIfPossible(NAME_FULL,
base::UTF8ToUTF16("The Dark Knight"),
VerificationStatus::kUserVerified);
EXPECT_TRUE(right.CompleteFullTree());
EXPECT_EQ(right.GetValueForType(NAME_FULL),
base::UTF8ToUTF16("The Dark Knight"));
EXPECT_EQ(right.GetValueForType(NAME_FIRST), base::UTF8ToUTF16("The"));
EXPECT_EQ(right.GetValueForType(NAME_MIDDLE), base::UTF8ToUTF16("Dark"));
EXPECT_EQ(right.GetValueForType(NAME_LAST), base::UTF8ToUTF16("Knight"));
EXPECT_EQ(right.GetVerificationStatusForType(NAME_FULL),
VerificationStatus::kUserVerified);
EXPECT_EQ(right.GetVerificationStatusForType(NAME_FIRST),
VerificationStatus::kParsed);
EXPECT_EQ(right.GetVerificationStatusForType(NAME_LAST),
VerificationStatus::kParsed);
EXPECT_EQ(right.GetVerificationStatusForType(NAME_MIDDLE),
VerificationStatus::kParsed);
EXPECT_FALSE(left == right);
EXPECT_TRUE(left != right);
// Set left to the same values as right and verify that it is now equal.
TestCompoundNameAddressComponent same_right;
same_right.SetValueForTypeIfPossible(NAME_FULL,
base::UTF8ToUTF16("The Dark Knight"),
VerificationStatus::kUserVerified);
EXPECT_TRUE(same_right.CompleteFullTree());
EXPECT_TRUE(right == same_right);
EXPECT_FALSE(right != same_right);
// Change one subcomponent and verify that it is not equal anymore.
same_right.SetValueForTypeIfPossible(NAME_LAST, base::UTF8ToUTF16("Joker"),
VerificationStatus::kParsed);
EXPECT_TRUE(right != same_right);
EXPECT_FALSE(right == same_right);
}
// Tests the assignment operator.
TEST(AutofillStructuredAddressAddressComponent, TestAssignmentOperator_Atom) {
AddressComponent left(NAME_FIRST);
AddressComponent right(NAME_FIRST);
left.SetValue(base::UTF8ToUTF16("some value"), VerificationStatus::kParsed);
right.SetValue(base::UTF8ToUTF16("some other value"),
VerificationStatus::kFormatted);
EXPECT_FALSE(left == right);
left.SetValue(base::UTF8ToUTF16("some other value"),
VerificationStatus::kFormatted);
EXPECT_TRUE(left == right);
}
// Tests the assignment operator on a compound node.
TEST(AutofillStructuredAddressAddressComponent,
TestAssignmentOperator_Compound) {
TestCompoundNameAddressComponent left;
TestCompoundNameAddressComponent right;
left.SetValueForTypeIfPossible(NAME_FULL,
base::UTF8ToUTF16("First Middle Last"),
VerificationStatus::kObserved);
left.RecursivelyCompleteTree();
right.SetValueForTypeIfPossible(NAME_FULL,
base::UTF8ToUTF16("The Dark Knight"),
VerificationStatus::kParsed);
right.RecursivelyCompleteTree();
EXPECT_FALSE(left == right);
left = right;
EXPECT_TRUE(left == right);
}
// Tests that self-assignment does not break things.
TEST(AutofillStructuredAddressAddressComponent, SelfAssignment) {
TestCompoundNameAddressComponent left;
left.SetValueForTypeIfPossible(NAME_FULL,
base::UTF8ToUTF16("First Middle Last"),
VerificationStatus::kObserved);
left = *(&left);
EXPECT_EQ(left.GetValueForType(NAME_FULL),
base::UTF8ToUTF16("First Middle Last"));
}
// Tests that the correct storage types are returned.
TEST(AutofillStructuredAddressAddressComponent, GetStorageType) {
EXPECT_EQ(TestAtomicFirstNameAddressComponent().GetStorageType(), NAME_FIRST);
EXPECT_EQ(TestAtomicMiddleNameAddressComponent().GetStorageType(),
NAME_MIDDLE);
EXPECT_EQ(TestAtomicLastNameAddressComponent().GetStorageType(), NAME_LAST);
EXPECT_EQ(TestCompoundNameAddressComponent().GetStorageType(), NAME_FULL);
}
// Tests that the correct storage type names are returned.
TEST(AutofillStructuredAddressAddressComponent, GetStorageTypeName) {
EXPECT_EQ(TestAtomicFirstNameAddressComponent().GetStorageTypeName(),
"NAME_FIRST");
EXPECT_EQ(TestAtomicMiddleNameAddressComponent().GetStorageTypeName(),
"NAME_MIDDLE");
EXPECT_EQ(TestAtomicLastNameAddressComponent().GetStorageTypeName(),
"NAME_LAST");
EXPECT_EQ(TestCompoundNameAddressComponent().GetStorageTypeName(),
"NAME_FULL");
}
// Tests that the correct atomicity is returned.
TEST(AutofillStructuredAddressAddressComponent, GetAtomicity) {
EXPECT_TRUE(TestAtomicFirstNameAddressComponent().IsAtomic());
EXPECT_TRUE(TestAtomicMiddleNameAddressComponent().IsAtomic());
EXPECT_TRUE(TestAtomicLastNameAddressComponent().IsAtomic());
EXPECT_FALSE(TestCompoundNameAddressComponent().IsAtomic());
}
// Tests directly setting and retrieving values.
TEST(AutofillStructuredAddressAddressComponent, DirectlyGetSetAndUnsetValue) {
base::string16 test_value = base::ASCIIToUTF16("test_value");
// Create an atomic structured component and verify its initial unset state
TestAtomicFirstNameAddressComponent first_name_component;
EXPECT_EQ(first_name_component.GetValue(), base::string16());
EXPECT_FALSE(first_name_component.IsValueAssigned());
EXPECT_EQ(first_name_component.GetVerificationStatus(),
VerificationStatus::kNoStatus);
// Set the value and the verification status and verify the set state.
first_name_component.SetValue(test_value, VerificationStatus::kObserved);
EXPECT_EQ(first_name_component.GetValue(), test_value);
EXPECT_TRUE(first_name_component.IsValueAssigned());
EXPECT_EQ(first_name_component.GetVerificationStatus(),
VerificationStatus::kObserved);
// Unset the value and verify the unset state again.
first_name_component.UnsetValue();
EXPECT_EQ(first_name_component.GetValue(), base::string16());
EXPECT_FALSE(first_name_component.IsValueAssigned());
EXPECT_EQ(first_name_component.GetVerificationStatus(),
VerificationStatus::kNoStatus);
}
// Tests recursively setting and retrieving values.
TEST(AutofillStructuredAddressAddressComponent,
RecursivelySettingAndGettingValues) {
base::string16 test_value = base::ASCIIToUTF16("test_value");
// Create a compound component that has a child of type NAME_FIRST.
TestCompoundNameAddressComponent compound_component;
// Set the value and verification status of a type not present in the tree and
// verify the failure.
bool success = compound_component.SetValueForTypeIfPossible(
ADDRESS_HOME_COUNTRY, test_value, VerificationStatus::kObserved);
EXPECT_FALSE(success);
// Set the value and verification status of a type that is a subcomponent of
// the compound and verify the success.
EXPECT_TRUE(compound_component.SetValueForTypeIfPossible(
NAME_FIRST, test_value, VerificationStatus::kObserved));
// Retrieve the value and verification status, verify the success and
// retrieved values.
base::string16 retrieved_value;
VerificationStatus retrieved_status;
EXPECT_TRUE(compound_component.GetValueAndStatusForTypeIfPossible(
NAME_FIRST, &retrieved_value, &retrieved_status));
EXPECT_EQ(retrieved_value, test_value);
EXPECT_EQ(retrieved_status, VerificationStatus::kObserved);
// Retrieve the value of a non-existing type and verify the failure.
EXPECT_FALSE(compound_component.GetValueAndStatusForTypeIfPossible(
ADDRESS_HOME_COUNTRY, &retrieved_value, &retrieved_status));
}
// Tests retrieving the subcomponents types.
TEST(AutofillStructuredAddressAddressComponent, GetSubcomponentTypes) {
// Create a compound component that has the subcomponents
// NAME_FIRST, NAME_MIDDLE, NAME_LAST.
TestCompoundNameAddressComponent compound_component;
// Get the subcomponent types and verify the expectation.
auto sub_component_types =
compound_component.GetSubcomponentTypesForTesting();
std::vector<ServerFieldType> expected_types{NAME_FIRST, NAME_MIDDLE,
NAME_LAST};
EXPECT_EQ(sub_component_types, expected_types);
}
// Tests getting the best format string for an atom.
TEST(AutofillStructuredAddressAddressComponent, GetBestFormatString_ForAtom) {
TestAtomicFirstNameAddressComponent first_name_component;
EXPECT_EQ(first_name_component.GetBestFormatStringForTesting(),
base::UTF8ToUTF16("${NAME_FIRST}"));
}
// Tests getting the best format string using the fallback mechanism.
TEST(AutofillStructuredAddressAddressComponent,
GetBestFormatString_WithFallback) {
// Create a compound component.
TestCompoundNameAddressComponent compound_component;
// Verify the retrieved default format string against the expectation.
base::string16 expected_result =
ASCIIToUTF16("${NAME_FIRST} ${NAME_MIDDLE} ${NAME_LAST}");
base::string16 actual_result =
compound_component.GetBestFormatStringForTesting();
EXPECT_EQ(expected_result, actual_result);
}
// Tests getting the best format string using the fallback mechanism.
TEST(AutofillStructuredAddressAddressComponent,
GetBestFormatString_WithCustomMethod) {
// Create a compound component.
TestCompoundNameCustomFormatAddressComponent compound_component;
// Verify the retrieved custom format string against the expectation.
base::string16 expected_result = ASCIIToUTF16("${NAME_LAST}, ${NAME_FIRST}");
base::string16 actual_result =
compound_component.GetBestFormatStringForTesting();
EXPECT_EQ(expected_result, actual_result);
}
// Tests formatting the unstructured value from the subcomponents with an
// unsupported token.
TEST(AutofillStructuredAddressAddressComponent,
FormatValueFromSubcomponents_UnsupportedToken) {
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
// Create a compound component and set the values.
TestCompoundNameCustomFormatWithUnsupportedTokenAddressComponent
compound_component;
compound_component.SetValueForTypeIfPossible(
NAME_FIRST, first_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_LAST, last_name, VerificationStatus::kUserVerified);
compound_component.FormatValueFromSubcomponentsForTesting();
base::string16 expected_value =
ASCIIToUTF16("Smith, Winston ${NOT_SUPPORTED}");
base::string16 actual_value = compound_component.GetValue();
EXPECT_EQ(expected_value, actual_value);
}
// Tests formatting the unstructured value from the subcomponents.
TEST(AutofillStructuredAddressAddressComponent, FormatValueFromSubcomponents) {
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
// Create a compound component and set the values.
TestCompoundNameAddressComponent compound_component;
compound_component.SetValueForTypeIfPossible(
NAME_FIRST, first_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_LAST, last_name, VerificationStatus::kUserVerified);
compound_component.FormatValueFromSubcomponentsForTesting();
base::string16 expected_value = ASCIIToUTF16("Winston O'Brien Smith");
base::string16 actual_value = compound_component.GetValue();
EXPECT_EQ(expected_value, actual_value);
}
// Tests that formatted values are correctly trimmed.
TEST(AutofillStructuredAddressAddressComponent,
FormatAndTrimmValueFromSubcomponents) {
base::string16 first_name = ASCIIToUTF16("");
base::string16 middle_name = ASCIIToUTF16("O'Brien ");
base::string16 last_name = ASCIIToUTF16("Smith");
// Create a compound component.
TestCompoundNameAddressComponent compound_component;
// Set the values of the components.
compound_component.SetValueForTypeIfPossible(
NAME_FIRST, first_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_LAST, last_name, VerificationStatus::kUserVerified);
compound_component.FormatValueFromSubcomponentsForTesting();
// Expect that the leading whitespace due to the missing first name and the
// double white spaces after the middle name are correctly trimmed.
base::string16 expected_value = ASCIIToUTF16("O'Brien Smith");
base::string16 actual_value = compound_component.GetValue();
EXPECT_EQ(expected_value, actual_value);
}
TEST(AutofillStructuredAddressAddressComponent,
TestEquivalenceOfReplacePlaceholderImplementations) {
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
// Create a compound component.
TestCompoundNameCustomFormatAddressComponent compound_component;
// Set the values of the subcomponents.
compound_component.SetValueForTypeIfPossible(
NAME_FIRST, first_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_LAST, last_name, VerificationStatus::kUserVerified);
}
// Tests the formatting of the unstructured value from the components with a
// type-specific format string.
TEST(AutofillStructuredAddressAddressComponent,
FormatValueFromSubcomponentsWithTypeSpecificFormat) {
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
// Create a compound component.
TestCompoundNameCustomFormatAddressComponent compound_component;
// Set the values of the subcomponents.
compound_component.SetValueForTypeIfPossible(
NAME_FIRST, first_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_LAST, last_name, VerificationStatus::kUserVerified);
// Format the compound and verify the expectation.
compound_component.FormatValueFromSubcomponentsForTesting();
base::string16 expected_value = ASCIIToUTF16("Smith, Winston");
base::string16 actual_value = compound_component.GetValue();
EXPECT_EQ(expected_value, actual_value);
}
// Tests parsing of an empty value. Because, that's why.
TEST(AutofillStructuredAddressAddressComponent,
TestParseValueAndAssignSubcomponentsByFallbackMethod_EmptyString) {
TestCompoundNameAddressComponent compound_component;
compound_component.SetValue(base::string16(), VerificationStatus::kObserved);
compound_component.ParseValueAndAssignSubcomponents();
EXPECT_EQ(compound_component.GetValue(), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
}
// Tests parsing using a defined method.
TEST(AutofillStructuredAddressAddressComponent,
TestParseValueAndAssignSubcomponentsByMethod) {
TestCompoundNameMethodParsedAddressComponent compound_component;
compound_component.SetValue(ASCIIToUTF16("Dr. Strangelove"),
VerificationStatus::kObserved);
compound_component.ParseValueAndAssignSubcomponents();
EXPECT_EQ(compound_component.GetValue(), ASCIIToUTF16("Dr. Strangelove"));
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST),
ASCIIToUTF16("Dr. Strangelove"));
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
}
// Tests parsing using a defined method.
TEST(AutofillStructuredAddressAddressComponent,
TestParseValueAndAssignSubcomponentsByExpression) {
TestCompoundNameExpressionParsedAddressComponent compound_component;
compound_component.SetValue(ASCIIToUTF16("Dr. Strangelove"),
VerificationStatus::kObserved);
compound_component.ParseValueAndAssignSubcomponents();
EXPECT_EQ(compound_component.GetValue(), ASCIIToUTF16("Dr. Strangelove"));
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST),
ASCIIToUTF16("Dr. Strangelove"));
}
// Go nuclear and parse the value of an atomic component.
TEST(AutofillStructuredAddressAddressComponent,
TestParseValueAndAssignSubcomponentsByFallbackMethod_Atom) {
TestAtomicFirstNameAddressComponent atomic_component;
atomic_component.SetValue(base::UTF8ToUTF16("Dangerzone"),
VerificationStatus::kObserved);
atomic_component.ParseValueAndAssignSubcomponents();
// The parsing should not crash the browser and keep the initial value intact.
EXPECT_EQ(base::UTF8ToUTF16("Dangerzone"), atomic_component.GetValue());
}
// Tests the fallback method to parse a value into its components if there are
// more space-separated tokens than components.
TEST(AutofillStructuredAddressAddressComponent,
TestParseValueAndAssignSubcomponentsByFallbackMethod) {
base::string16 full_name = ASCIIToUTF16("Winston O'Brien Hammer Smith");
// Create a compound component, set the value and parse the value of the
// subcomponents.
TestCompoundNameAddressComponent compound_component;
compound_component.SetValueForTypeIfPossible(
NAME_FULL, full_name, VerificationStatus::kUserVerified);
compound_component.ParseValueAndAssignSubcomponents();
// Define the expectations, and verify the expectation.
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Hammer Smith");
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
}
// Tests the fallback method to parse a value into its components if there are
// less space-separated tokens than components.
TEST(AutofillStructuredAddressAddressComponent,
ParseValueAndAssignSubcomponentsByFallbackMethod_WithFewTokens) {
base::string16 full_name = ASCIIToUTF16("Winston");
// Create a compound component and assign a value.
TestCompoundNameAddressComponent compound_component;
compound_component.SetValueForTypeIfPossible(
NAME_FULL, full_name, VerificationStatus::kUserVerified);
// Parse the full name into its components by using the fallback method
compound_component.ParseValueAndAssignSubcomponents();
// Verify the expectation.
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("");
base::string16 last_name = ASCIIToUTF16("");
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
}
// Tests that a tree is regarded completable if and only if there if the
// maximum number of assigned nodes on a path from the root node to a leaf is
// exactly one.
TEST(AutofillStructuredAddressAddressComponent, IsTreeCompletable) {
// Some values.
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
// Create a compound component.
TestCompoundNameAddressComponent compound_component;
// This tree is not completable because it has not a single assigned node.
EXPECT_FALSE(compound_component.IsTreeCompletable());
// Set the first name node of the tree.
compound_component.SetValueForTypeIfPossible(
NAME_FIRST, first_name, VerificationStatus::kUserVerified);
// The tree should be completable because there is exactly one assigned node.
EXPECT_TRUE(compound_component.IsTreeCompletable());
// Set the middle-name node of the tree.
compound_component.SetValueForTypeIfPossible(
NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
// The tree should still be completable because the first and middle name are
// siblings and not in a direct line.
EXPECT_TRUE(compound_component.IsTreeCompletable());
// Set the full name node of the tree.
compound_component.SetValueForTypeIfPossible(
NAME_FULL, full_name, VerificationStatus::kUserVerified);
// Now, the tree is not completable anymore because there are multiple
// assigned values on a path from the root to a leaf.
EXPECT_FALSE(compound_component.IsTreeCompletable());
EXPECT_FALSE(compound_component.CompleteFullTree());
}
// Tests that the tree is completed successfully from the root node down to the
// leafs.
TEST(AutofillStructuredAddressAddressComponent, TreeCompletion_TopToBottom) {
// Some values.
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
// Create a compound component and set the value of the root node.
TestCompoundNameAddressComponent compound_component;
compound_component.SetValueForTypeIfPossible(
NAME_FULL, full_name, VerificationStatus::kUserVerified);
// Verify that the are subcomponents empty.
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
// Complete the tree.
EXPECT_TRUE(compound_component.CompleteFullTree());
// Verify that the values for the subcomponents have been successfully parsed.
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
}
// Tests that the tree is completed successfully from leaf nodes to the root.
TEST(AutofillStructuredAddressAddressComponent, TreeCompletion_BottomToTop) {
// Some values.
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
// Create a compound component and set the value of the first, middle and last
// name.
TestCompoundNameAddressComponent compound_component;
compound_component.SetValueForTypeIfPossible(
NAME_FIRST, first_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_MIDDLE, middle_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_LAST, last_name, VerificationStatus::kUserVerified);
// Verify that the root node is empty.
EXPECT_EQ(compound_component.GetValueForType(NAME_FULL), base::string16());
// Complete the tree.
compound_component.CompleteFullTree();
// Verify that the value for the root node was successfully formatted.
EXPECT_EQ(compound_component.GetValueForType(NAME_FULL), full_name);
}
// Tests that the tree is completed successfully both upwards and downwards when
// a node with both subcomponents and a parent is set.
TEST(AutofillStructuredAddressAddressComponent, TreeCompletion_ToTopAndBottom) {
// Define Some values.
base::string16 title = ASCIIToUTF16("Dr.");
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
base::string16 full_name_with_title =
ASCIIToUTF16("Dr. Winston O'Brien Smith");
// Create a compound component.
TestCompoundNameWithTitleAddressComponent compound_component;
// Set the value of the root node.
compound_component.SetValueForTypeIfPossible(
NAME_FULL, full_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_HONORIFIC_PREFIX, title, VerificationStatus::kUserVerified);
// Verify that the are subcomponents empty.
// CREDIT_CARD_NAME_FULL is a fictive type containing a title and a full name.
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
// Complete the tree.
compound_component.CompleteFullTree();
// Verify that the values for the subcomponents have been successfully parsed
// and the parent node was probably formatted.
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
full_name_with_title);
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
}
// Test that values are invalidated correctly.
TEST(AutofillStructuredAddressAddressComponent,
TestSettingsValuesWithInvalidation) {
// Define Some values.
base::string16 title = ASCIIToUTF16("Dr.");
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
base::string16 full_name_with_title =
ASCIIToUTF16("Dr. Winston O'Brien Smith");
// Create a compound component.
TestCompoundNameWithTitleAddressComponent compound_component;
// Set the value of the root node.
compound_component.SetValueForTypeIfPossible(
NAME_FULL, full_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_HONORIFIC_PREFIX, title, VerificationStatus::kUserVerified);
// Verify that the are subcomponents empty.
// CREDIT_CARD_NAME_FULL is a fictive type containing a title and a full name.
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
// Complete the tree.
compound_component.CompleteFullTree();
// Verify that the values for the subcomponents have been successfully parsed
// and the parent node was probably formatted.
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
full_name_with_title);
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
// Change the value of FULL_NAME and invalidate all child and ancestor nodes.
compound_component.SetValueForTypeIfPossible(
NAME_FULL, base::UTF8ToUTF16("Oh' Brian"), VerificationStatus::kObserved,
true, true);
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
}
// Test unsetting a value and its subcomponents.
TEST(AutofillStructuredAddressAddressComponent,
TestUnsettingAValueAndItsSubcomponents) {
// Define Some values.
base::string16 title = ASCIIToUTF16("Dr.");
base::string16 first_name = ASCIIToUTF16("Winston");
base::string16 middle_name = ASCIIToUTF16("O'Brien");
base::string16 last_name = ASCIIToUTF16("Smith");
base::string16 full_name = ASCIIToUTF16("Winston O'Brien Smith");
base::string16 full_name_with_title =
ASCIIToUTF16("Dr. Winston O'Brien Smith");
// Create a compound component.
TestCompoundNameWithTitleAddressComponent compound_component;
// Set the value of the root node.
compound_component.SetValueForTypeIfPossible(
NAME_FULL, full_name, VerificationStatus::kUserVerified);
compound_component.SetValueForTypeIfPossible(
NAME_HONORIFIC_PREFIX, title, VerificationStatus::kUserVerified);
// Verify that the are subcomponents empty.
// CREDIT_CARD_NAME_FULL is a fictive type containing a title and a full name.
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
// Complete the tree.
compound_component.CompleteFullTree();
// Verify that the values for the subcomponents have been successfully parsed
// and the parent node was probably formatted.
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
full_name_with_title);
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), first_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), middle_name);
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), last_name);
// Change the value of FULL_NAME and invalidate all child and ancestor nodes.
compound_component.UnsetValueForTypeIfSupported(NAME_FULL);
EXPECT_EQ(compound_component.GetValueForType(CREDIT_CARD_NAME_FULL),
full_name_with_title);
EXPECT_EQ(compound_component.GetValueForType(NAME_FIRST), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_MIDDLE), base::string16());
EXPECT_EQ(compound_component.GetValueForType(NAME_LAST), base::string16());
}
// Tests that the tree is completed successfully both upwards and downwards when
// a node with both subcomponents and a parent is set.
TEST(AutofillStructuredAddressAddressComponent,
TestUnsettingParsedAndFormatedValues) {
// Define Some values.
TestCompoundNameWithTitleAddressComponent compound_component;
// Set a value somewhere in the tree, complete and verify that another node is
// assigned.
compound_component.SetValueForTypeIfPossible(
NAME_FULL, base::UTF8ToUTF16("Winston Brian Smith"),
VerificationStatus::kObserved);
EXPECT_EQ(VerificationStatus::kObserved,
compound_component.GetVerificationStatusForType(NAME_FULL));
compound_component.CompleteFullTree();
EXPECT_EQ(VerificationStatus::kParsed,
compound_component.GetVerificationStatusForType(NAME_MIDDLE));
EXPECT_EQ(
VerificationStatus::kFormatted,
compound_component.GetVerificationStatusForType(CREDIT_CARD_NAME_FULL));
// Clear parsed and formatted values and verify the expectation.
compound_component.UnsetParsedAndFormattedValuesInEntireTree();
EXPECT_EQ(VerificationStatus::kObserved,
compound_component.GetVerificationStatusForType(NAME_FULL));
EXPECT_EQ(VerificationStatus::kNoStatus,
compound_component.GetVerificationStatusForType(NAME_MIDDLE));
EXPECT_EQ(
VerificationStatus::kNoStatus,
compound_component.GetVerificationStatusForType(CREDIT_CARD_NAME_FULL));
}
} // namespace structured_address
} // namespace autofill
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