blob: 8511690c0a20665bb352667112766d96d2871a36 [file] [log] [blame]
// 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_assistant/browser/value_util.h"
#include <algorithm>
#include "base/i18n/case_conversion.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
namespace autofill_assistant {
// Compares two 'repeated' fields and returns true if every element matches.
template <typename T>
bool RepeatedFieldEquals(const T& values_a, const T& values_b) {
if (values_a.size() != values_b.size()) {
return false;
}
for (int i = 0; i < values_a.size(); i++) {
if (!(values_a[i] == values_b[i])) {
return false;
}
}
return true;
}
// '==' operator specialization for RepeatedPtrField.
template <typename T>
bool operator==(const google::protobuf::RepeatedPtrField<T>& values_a,
const google::protobuf::RepeatedPtrField<T>& values_b) {
return RepeatedFieldEquals(values_a, values_b);
}
// '==' operator specialization for RepeatedField.
template <typename T>
bool operator==(const google::protobuf::RepeatedField<T>& values_a,
const google::protobuf::RepeatedField<T>& values_b) {
return RepeatedFieldEquals(values_a, values_b);
}
// Compares two |ValueProto| instances and returns true if they exactly match.
bool operator==(const ValueProto& value_a, const ValueProto& value_b) {
if (value_a.kind_case() != value_b.kind_case()) {
return false;
}
switch (value_a.kind_case()) {
case ValueProto::kStrings:
return value_a.strings().values() == value_b.strings().values();
case ValueProto::kBooleans:
return value_a.booleans().values() == value_b.booleans().values();
case ValueProto::kInts:
return value_a.ints().values() == value_b.ints().values();
case ValueProto::kUserActions:
return value_a.user_actions().values() == value_b.user_actions().values();
case ValueProto::kDates:
return value_a.dates().values() == value_b.dates().values();
case ValueProto::kCreditCards:
return value_a.credit_cards().values() == value_b.credit_cards().values();
case ValueProto::kProfiles:
return value_a.profiles().values() == value_b.profiles().values();
case ValueProto::kLoginOptions:
return value_a.login_options().values() ==
value_b.login_options().values();
case ValueProto::kCreditCardResponse:
return value_a.credit_card_response() == value_b.credit_card_response();
case ValueProto::kLoginOptionResponse:
return value_a.login_option_response() == value_b.login_option_response();
case ValueProto::KIND_NOT_SET:
return true;
}
return true;
}
bool operator!=(const ValueProto& value_a, const ValueProto& value_b) {
return !(value_a == value_b);
}
bool operator<(const ValueProto& value_a, const ValueProto& value_b) {
if (value_a.kind_case() != value_b.kind_case()) {
return false;
}
if (!AreAllValuesOfSize({value_a, value_b}, 1)) {
return false;
}
switch (value_a.kind_case()) {
case ValueProto::kStrings:
return base::i18n::FoldCase(
base::UTF8ToUTF16(value_a.strings().values(0))) <
base::i18n::FoldCase(
base::UTF8ToUTF16(value_b.strings().values(0)));
case ValueProto::kInts:
return value_a.ints().values(0) < value_b.ints().values(0);
case ValueProto::kDates:
return value_a.dates().values(0) < value_b.dates().values(0);
case ValueProto::kUserActions:
case ValueProto::kBooleans:
case ValueProto::kCreditCards:
case ValueProto::kProfiles:
case ValueProto::kLoginOptions:
case ValueProto::kCreditCardResponse:
case ValueProto::kLoginOptionResponse:
case ValueProto::KIND_NOT_SET:
NOTREACHED();
return false;
}
return true;
}
bool operator>(const ValueProto& value_a, const ValueProto& value_b) {
return value_b < value_a && !(value_b == value_a);
}
// Compares two |ModelValue| instances and returns true if they exactly match.
bool operator==(const ModelProto::ModelValue& value_a,
const ModelProto::ModelValue& value_b) {
return value_a.identifier() == value_b.identifier() &&
value_a.value() == value_b.value();
}
// Compares two |ChipProto| instances and returns true if they exactly match.
bool operator==(const ChipProto& value_a, const ChipProto& value_b) {
return value_a.type() == value_b.type() && value_a.icon() == value_b.icon() &&
value_a.text() == value_b.text() &&
value_a.sticky() == value_b.sticky();
}
// Compares two |DirectActionProto| instances and returns true if they exactly
// match.
bool operator==(const DirectActionProto& value_a,
const DirectActionProto& value_b) {
return RepeatedFieldEquals(value_a.names(), value_b.names()) &&
RepeatedFieldEquals(value_a.required_arguments(),
value_b.required_arguments()) &&
RepeatedFieldEquals(value_a.optional_arguments(),
value_b.optional_arguments());
}
// Compares two |UserActionProto| instances and returns true if they exactly
// match.
bool operator==(const UserActionProto& value_a,
const UserActionProto& value_b) {
return value_a.chip() == value_b.chip() &&
value_a.direct_action() == value_b.direct_action() &&
value_a.identifier() == value_b.identifier() &&
value_a.enabled() == value_b.enabled();
}
// Compares two |DateProto| instances and returns true if they exactly match.
bool operator==(const DateProto& value_a, const DateProto& value_b) {
return value_a.year() == value_b.year() &&
value_a.month() == value_b.month() && value_a.day() == value_b.day();
}
bool operator<(const DateProto& value_a, const DateProto& value_b) {
auto tuple_a =
std::make_tuple(value_a.year(), value_a.month(), value_a.day());
auto tuple_b =
std::make_tuple(value_b.year(), value_b.month(), value_b.day());
return tuple_a < tuple_b;
}
bool operator==(const AutofillCreditCardProto& value_a,
const AutofillCreditCardProto& value_b) {
return value_a.guid() == value_b.guid();
}
bool operator==(const AutofillProfileProto& value_a,
const AutofillProfileProto& value_b) {
return value_a.guid() == value_b.guid();
}
bool operator==(const LoginOptionProto& value_a,
const LoginOptionProto& value_b) {
return value_a.label() == value_b.label() &&
value_a.sublabel() == value_b.sublabel() &&
value_a.payload() == value_b.payload();
}
bool operator==(const CreditCardResponseProto& value_a,
const CreditCardResponseProto& value_b) {
return value_a.network() == value_b.network();
}
bool operator==(const LoginOptionResponseProto& value_a,
const LoginOptionResponseProto& value_b) {
return value_a.payload() == value_b.payload();
}
// Intended for debugging. Writes a string representation of |values| to |out|.
template <typename T>
std::ostream& WriteRepeatedField(std::ostream& out, const T& values) {
std::string separator = "";
out << "[";
for (const auto& value : values) {
out << separator << value;
separator = ", ";
}
out << "]";
return out;
}
// Intended for debugging. '<<' operator specialization for RepeatedPtrField.
template <typename T>
std::ostream& operator<<(std::ostream& out,
const google::protobuf::RepeatedPtrField<T>& values) {
return WriteRepeatedField(out, values);
}
// Intended for debugging. '<<' operator specialization for RepeatedField.
template <typename T>
std::ostream& operator<<(std::ostream& out,
const google::protobuf::RepeatedField<T>& values) {
return WriteRepeatedField(out, values);
}
std::ostream& operator<<(std::ostream& out, const UserActionProto& value) {
out << value.identifier();
return out;
}
std::ostream& operator<<(std::ostream& out, const DateProto& value) {
out << value.year() << "-" << value.month() << "-" << value.day();
return out;
}
std::ostream& operator<<(std::ostream& out,
const AutofillCreditCardProto& value) {
out << value.guid();
return out;
}
std::ostream& operator<<(std::ostream& out, const AutofillProfileProto& value) {
out << value.guid();
return out;
}
std::ostream& operator<<(std::ostream& out, const LoginOptionProto& value) {
out << value.label() << ", " << value.sublabel() << ", " << value.payload();
return out;
}
std::ostream& operator<<(std::ostream& out,
const CreditCardResponseProto& value) {
out << value.network();
return out;
}
std::ostream& operator<<(std::ostream& out,
const LoginOptionResponseProto& value) {
out << value.payload();
return out;
}
// Intended for debugging. Writes a string representation of |value| to |out|.
std::ostream& operator<<(std::ostream& out, const ValueProto& value) {
switch (value.kind_case()) {
case ValueProto::kStrings:
out << value.strings().values();
break;
case ValueProto::kBooleans:
out << value.booleans().values();
break;
case ValueProto::kInts:
out << value.ints().values();
break;
case ValueProto::kUserActions:
out << value.user_actions().values();
break;
case ValueProto::kDates:
out << value.dates().values();
break;
case ValueProto::kCreditCards:
out << value.credit_cards().values();
break;
case ValueProto::kProfiles:
out << value.profiles().values();
break;
case ValueProto::kLoginOptions:
out << value.login_options().values();
break;
case ValueProto::kCreditCardResponse:
out << value.credit_card_response();
break;
case ValueProto::kLoginOptionResponse:
out << value.login_option_response();
;
break;
case ValueProto::KIND_NOT_SET:
break;
}
if (value.is_client_side_only()) {
out << " (client-side-only)";
}
return out;
}
std::ostream& operator<<(std::ostream& out,
const ValueReferenceProto& reference) {
switch (reference.kind_case()) {
case ValueReferenceProto::kValue:
return out << reference.value();
case ValueReferenceProto::kModelIdentifier:
return out << reference.model_identifier();
case ValueReferenceProto::KIND_NOT_SET:
return out;
}
}
// Intended for debugging. Writes a string representation of |value| to |out|.
std::ostream& operator<<(std::ostream& out,
const ModelProto::ModelValue& value) {
out << value.identifier() << ": " << value.value();
return out;
}
// Convenience constructors.
ValueProto SimpleValue(bool b, bool is_client_side_only) {
ValueProto value;
value.mutable_booleans()->add_values(b);
if (is_client_side_only)
value.set_is_client_side_only(is_client_side_only);
return value;
}
ValueProto SimpleValue(const std::string& s, bool is_client_side_only) {
ValueProto value;
value.mutable_strings()->add_values(s);
if (is_client_side_only)
value.set_is_client_side_only(is_client_side_only);
return value;
}
ValueProto SimpleValue(int i, bool is_client_side_only) {
ValueProto value;
value.mutable_ints()->add_values(i);
if (is_client_side_only)
value.set_is_client_side_only(is_client_side_only);
return value;
}
ValueProto SimpleValue(const DateProto& proto, bool is_client_side_only) {
ValueProto value;
auto* date = value.mutable_dates()->add_values();
date->set_year(proto.year());
date->set_month(proto.month());
date->set_day(proto.day());
if (is_client_side_only)
value.set_is_client_side_only(is_client_side_only);
return value;
}
ModelProto::ModelValue SimpleModelValue(const std::string& identifier,
const ValueProto& value) {
ModelProto::ModelValue model_value;
model_value.set_identifier(identifier);
*model_value.mutable_value() = value;
return model_value;
}
bool AreAllValuesOfType(const std::vector<ValueProto>& values,
ValueProto::KindCase target_type) {
if (values.empty()) {
return false;
}
for (const auto& value : values) {
if (value.kind_case() != target_type) {
return false;
}
}
return true;
}
bool AreAllValuesOfSize(const std::vector<ValueProto>& values,
int target_size) {
if (values.empty()) {
return false;
}
for (const auto& value : values) {
if (GetValueSize(value) != target_size) {
return false;
}
}
return true;
}
bool ContainsClientOnlyValue(const std::vector<ValueProto>& values) {
for (const auto& value : values) {
if (value.is_client_side_only()) {
return true;
}
}
return false;
}
int GetValueSize(const ValueProto& value) {
switch (value.kind_case()) {
case ValueProto::kStrings:
return value.strings().values().size();
case ValueProto::kBooleans:
return value.booleans().values().size();
case ValueProto::kInts:
return value.ints().values().size();
case ValueProto::kUserActions:
return value.user_actions().values().size();
case ValueProto::kDates:
return value.dates().values().size();
case ValueProto::kCreditCards:
return value.credit_cards().values().size();
case ValueProto::kProfiles:
return value.profiles().values().size();
case ValueProto::kLoginOptions:
return value.login_options().values().size();
case ValueProto::kCreditCardResponse:
return 1;
case ValueProto::kLoginOptionResponse:
return 1;
case ValueProto::KIND_NOT_SET:
return 0;
}
}
base::Optional<ValueProto> GetNthValue(const ValueProto& value, int index) {
if (value == ValueProto()) {
return base::nullopt;
}
if (index < 0 || index >= GetValueSize(value)) {
return base::nullopt;
}
ValueProto nth_value;
if (value.is_client_side_only())
nth_value.set_is_client_side_only(value.is_client_side_only());
switch (value.kind_case()) {
case ValueProto::kStrings:
nth_value.mutable_strings()->add_values(
value.strings().values().at(index));
return nth_value;
case ValueProto::kBooleans:
nth_value.mutable_booleans()->add_values(
value.booleans().values().at(index));
return nth_value;
case ValueProto::kInts:
nth_value.mutable_ints()->add_values(value.ints().values().at(index));
return nth_value;
case ValueProto::kUserActions:
*nth_value.mutable_user_actions()->add_values() =
value.user_actions().values().at(index);
return nth_value;
case ValueProto::kDates:
*nth_value.mutable_dates()->add_values() =
value.dates().values().at(index);
return nth_value;
case ValueProto::kCreditCards:
*nth_value.mutable_credit_cards()->add_values() =
value.credit_cards().values().at(index);
return nth_value;
case ValueProto::kProfiles:
*nth_value.mutable_profiles()->add_values() =
value.profiles().values().at(index);
return nth_value;
case ValueProto::kLoginOptions:
*nth_value.mutable_login_options()->add_values() =
value.login_options().values().at(index);
return nth_value;
case ValueProto::kCreditCardResponse:
DCHECK(index == 0);
nth_value = value;
return nth_value;
case ValueProto::kLoginOptionResponse:
DCHECK(index == 0);
nth_value = value;
return nth_value;
case ValueProto::KIND_NOT_SET:
return base::nullopt;
}
}
} // namespace autofill_assistant