chromium/chromeos/components/quick_answers/search_result_parsers/unit_conversion_result_parser_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/components/quick_answers/search_result_parsers/unit_conversion_result_parser.h"

#include <memory>
#include <string>

#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chromeos/components/quick_answers/test/test_helpers.h"
#include "chromeos/components/quick_answers/test/unit_conversion_unittest_constants.h"
#include "chromeos/components/quick_answers/utils/quick_answers_utils.h"
#include "chromeos/components/quick_answers/utils/unit_conversion_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/color/color_id.h"

#define EXPECT_ROUNDED_DOUBLE_EQ(a, b)           \
  {                                              \
    double rounded_a = round(a * 100.0) / 100.0; \
    double rounded_b = round(b * 100.0) / 100.0; \
    EXPECT_DOUBLE_EQ(rounded_a, rounded_b);      \
  }

namespace quick_answers {
namespace {

using base::Value;
using Type = base::Value::Type;

inline constexpr char kTemperatureCategory[] = "Temperature";

inline constexpr double kCelciusRateA = 1.0;
inline constexpr double kCelciusRateB = 273.15;
inline constexpr char kCelciusName[] = "Degree Celcius";
inline constexpr double kFahrenheitRateA = 0.5555555555555556;
inline constexpr double kFahrenheitRateB = 255.3722222222222;
inline constexpr char kFahrenheitName[] = "Fahrenheit";
inline constexpr double kKelvinRateA = 1.0;
inline constexpr char kKelvinName[] = "Kelvin";

inline constexpr double kSourceAmountCelcius = 10.0;
inline constexpr double kDestAmountFahrenheit = 50.0;
inline constexpr double kDestAmountKelvin = 283.15;
inline constexpr char kSourceRawTextCelcius[] = "10 degrees celcius";
inline constexpr char kDestRawTextFahrenheit[] = "50 degrees fahrenheit";

inline constexpr char kFuelEconomyCategory[] = "Fuel Economy";

inline constexpr double kLiterPer100KilometersRateC = 100.0;
inline constexpr char kLiterPer100KilometersName[] = "Liter per 100 kilometers";
inline constexpr double kKilometerPerLiterRateA = 1.0;
inline constexpr char kKilometerPerLiterName[] = "Kilometer per liter";

inline constexpr double kSourceAmountLiterPer100Kilometers = 1.0;
inline constexpr double kDestAmountKilometerPerLiter = 100.0;
inline constexpr char kSourceRawTextLiterPer100Kilometers[] =
    "1 liter per 100 kilometers";
inline constexpr char kDestRawTextKilometerPerLiter[] =
    "100 kilometers per liter";

Value BuildMassRuleSet() {
  Value::List rule_set;
  Value::Dict conversion;
  Value::List units;

  conversion.Set(kCategoryPath, kMassCategory);
  units.Append(CreateUnit(kKilogramName, kKilogramRateA));
  units.Append(CreateUnit(kGramName, kGramRateA));
  units.Append(CreateUnit(kPoundName, kPoundRateA));
  units.Append(CreateUnit(kOunceName, kOunceRateA));
  conversion.Set(kUnitsPath, std::move(units));
  rule_set.Append(std::move(conversion));

  return Value(std::move(rule_set));
}

Value BuildTemperatureRuleSet() {
  Value::List rule_set;
  Value::Dict conversion;
  Value::List units;

  conversion.Set(kCategoryPath, kTemperatureCategory);
  units.Append(CreateUnit(kCelciusName, kCelciusRateA, kCelciusRateB));
  units.Append(CreateUnit(kFahrenheitName, kFahrenheitRateA, kFahrenheitRateB));
  units.Append(CreateUnit(kKelvinName, kKelvinRateA));
  conversion.Set(kUnitsPath, std::move(units));
  rule_set.Append(std::move(conversion));

  return Value(std::move(rule_set));
}

Value BuildFuelEconomyRuleSet() {
  Value::List rule_set;
  Value::Dict conversion;
  Value::List units;

  conversion.Set(kCategoryPath, kFuelEconomyCategory);
  units.Append(
      CreateUnit(kLiterPer100KilometersName, /*rate_a=*/kInvalidRateTermValue,
                 /*rate_b=*/kInvalidRateTermValue, /*category=*/std::string(),
                 kLiterPer100KilometersRateC));
  units.Append(CreateUnit(kKilometerPerLiterName, kKilometerPerLiterRateA));
  conversion.Set(kUnitsPath, std::move(units));
  rule_set.Append(std::move(conversion));

  return Value(std::move(rule_set));
}

}  // namespace

class UnitConversionResultParserTest : public testing::Test {
 public:
  UnitConversionResultParserTest() = default;

  UnitConversionResultParserTest(const UnitConversionResultParserTest&) =
      delete;
  UnitConversionResultParserTest& operator=(
      const UnitConversionResultParserTest&) = delete;

  void SetCategory(const std::string& category) {
    result_.SetByDottedPath(kResultCategoryPath, category);
  }

  void SetSourceText(const std::string& text) {
    result_.SetByDottedPath(kSourceTextPath, text);
  }

  void SetDestText(const std::string& text) {
    result_.SetByDottedPath(kDestTextPath, text);
  }

  void SetSourceAmount(const double value) {
    result_.SetByDottedPath(kSourceAmountPath, value);
  }

  void SetDestAmount(const double value) {
    result_.SetByDottedPath(kDestAmountPath, value);
  }

  void AddSourceUnit(Value::Dict src_unit) {
    result_.SetByDottedPath(kSourceUnitPath, std::move(src_unit));
  }

  void AddDestUnit(Value::Dict dest_unit) {
    result_.SetByDottedPath(kDestUnitPath, std::move(dest_unit));
  }

  void AddRuleSet(Value rule_set) {
    result_.SetByDottedPath(kRuleSetPath, std::move(rule_set));
  }

  bool Parse(QuickAnswer* quick_answer) {
    return parser_.Parse(result_, quick_answer);
  }

  std::unique_ptr<StructuredResult> ParseInStructuredResult() {
    return parser_.ParseInStructuredResult(result_);
  }

  std::string GetAmountString(double amount) {
    return base::StringPrintf(kResultValueTemplate, amount);
  }

 protected:
  Value::Dict result_;

  UnitConversionResultParser parser_;
};

TEST_F(UnitConversionResultParserTest, ParseWithEmptyValueShouldReturnFalse) {
  QuickAnswer quick_answer;

  EXPECT_FALSE(Parse(&quick_answer));
}

TEST_F(UnitConversionResultParserTest,
       ParseWithIncorrectTypeShouldReturnFalse) {
  result_.SetByDottedPath(kDestTextPath, 1);
  QuickAnswer quick_answer;

  EXPECT_FALSE(Parse(&quick_answer));
}

TEST_F(UnitConversionResultParserTest,
       ParseWithIncorrectPathShouldReturnFalse) {
  result_.Set("WrongPath", kDestRawTextPound);
  QuickAnswer quick_answer;

  EXPECT_FALSE(Parse(&quick_answer));
}

TEST_F(UnitConversionResultParserTest,
       ParseWithNoSourceUnitShouldReturnRawText) {
  SetCategory(kMassCategory);
  SetSourceText(kSourceRawTextKilogram);
  SetSourceAmount(kSourceAmountKilogram);
  SetDestText(kDestRawTextPound);
  SetDestAmount(kDestAmountPound);
  AddDestUnit(CreateUnit(kPoundName, kPoundRateA,
                         /*rate_b=*/kInvalidRateTermValue, kMassCategory));
  AddRuleSet(BuildMassRuleSet());

  QuickAnswer quick_answer;

  EXPECT_TRUE(Parse(&quick_answer));
  EXPECT_EQ(ResultType::kUnitConversionResult, quick_answer.result_type);

  EXPECT_EQ(1u, quick_answer.first_answer_row.size());
  EXPECT_EQ(0u, quick_answer.title.size());
  auto* answer =
      static_cast<QuickAnswerText*>(quick_answer.first_answer_row[0].get());
  EXPECT_EQ(kDestRawTextPound,
            GetQuickAnswerTextForTesting(quick_answer.first_answer_row));
  EXPECT_EQ(ui::kColorLabelForegroundSecondary, answer->color_id);

  // Expectations for `StructuredResult`.
  std::unique_ptr<StructuredResult> structured_result =
      ParseInStructuredResult();
  ASSERT_TRUE(structured_result);
  ASSERT_TRUE(structured_result->unit_conversion_result);

  UnitConversionResult* unit_conversion_result =
      structured_result->unit_conversion_result.get();
  EXPECT_EQ(unit_conversion_result->source_text, kSourceRawTextKilogram);
  EXPECT_EQ(unit_conversion_result->result_text,
            base::UTF16ToASCII(answer->text));
  EXPECT_EQ(unit_conversion_result->category, kMassCategory);
  EXPECT_EQ(unit_conversion_result->source_amount, kSourceAmountKilogram);
  EXPECT_FALSE(unit_conversion_result->source_to_dest_unit_conversion);
  EXPECT_TRUE(
      unit_conversion_result->alternative_unit_conversions_list.empty());
}

TEST_F(UnitConversionResultParserTest, ParseWithNoRuleSetShouldReturnRawText) {
  SetCategory(kMassCategory);
  SetSourceText(kSourceRawTextKilogram);
  SetSourceAmount(kSourceAmountKilogram);
  SetDestText(kDestRawTextPound);
  SetDestAmount(kDestAmountPound);
  AddSourceUnit(CreateUnit(kKilogramName, kKilogramRateA,
                           /*rate_b=*/kInvalidRateTermValue, kMassCategory));
  AddDestUnit(CreateUnit(kPoundName, kPoundRateA,
                         /*rate_b=*/kInvalidRateTermValue, kMassCategory));

  QuickAnswer quick_answer;

  EXPECT_TRUE(Parse(&quick_answer));
  EXPECT_EQ(ResultType::kUnitConversionResult, quick_answer.result_type);

  EXPECT_EQ(1u, quick_answer.first_answer_row.size());
  EXPECT_EQ(0u, quick_answer.title.size());
  auto* answer =
      static_cast<QuickAnswerText*>(quick_answer.first_answer_row[0].get());
  EXPECT_EQ(kDestRawTextPound,
            GetQuickAnswerTextForTesting(quick_answer.first_answer_row));
  EXPECT_EQ(ui::kColorLabelForegroundSecondary, answer->color_id);

  // Expectations for `StructuredResult`.
  std::unique_ptr<StructuredResult> structured_result =
      ParseInStructuredResult();
  ASSERT_TRUE(structured_result);
  ASSERT_TRUE(structured_result->unit_conversion_result);

  UnitConversionResult* unit_conversion_result =
      structured_result->unit_conversion_result.get();
  EXPECT_EQ(unit_conversion_result->source_text, kSourceRawTextKilogram);
  EXPECT_EQ(unit_conversion_result->result_text,
            base::UTF16ToASCII(answer->text));
  EXPECT_EQ(unit_conversion_result->category, kMassCategory);
  EXPECT_EQ(unit_conversion_result->source_amount, kSourceAmountKilogram);

  ASSERT_TRUE(structured_result->unit_conversion_result
                  ->source_to_dest_unit_conversion);
  UnitConversion conversion_rate =
      unit_conversion_result->source_to_dest_unit_conversion.value();
  EXPECT_EQ(conversion_rate.category(), kMassCategory);
  EXPECT_EQ(conversion_rate.source_rule().unit_name(), kKilogramName);
  EXPECT_EQ(conversion_rate.dest_rule().unit_name(), kPoundName);
  EXPECT_ROUNDED_DOUBLE_EQ(
      conversion_rate.ConvertSourceAmountToDestAmount(kSourceAmountKilogram),
      kDestAmountPound);

  EXPECT_TRUE(
      unit_conversion_result->alternative_unit_conversions_list.empty());
}

TEST_F(UnitConversionResultParserTest,
       ParseWithResultWithinPreferredRangeShouldReturnRawText) {
  SetCategory(kMassCategory);
  SetSourceText(kSourceRawTextKilogram);
  SetSourceAmount(kSourceAmountKilogram);
  SetDestText(kDestRawTextPound);
  SetDestAmount(kDestAmountPound);
  AddSourceUnit(CreateUnit(kKilogramName, kKilogramRateA,
                           /*rate_b=*/kInvalidRateTermValue, kMassCategory));
  AddDestUnit(CreateUnit(kPoundName, kPoundRateA,
                         /*rate_b=*/kInvalidRateTermValue, kMassCategory));
  AddRuleSet(BuildMassRuleSet());

  QuickAnswer quick_answer;

  EXPECT_TRUE(Parse(&quick_answer));
  EXPECT_EQ(ResultType::kUnitConversionResult, quick_answer.result_type);

  EXPECT_EQ(1u, quick_answer.first_answer_row.size());
  EXPECT_EQ(0u, quick_answer.title.size());
  auto* answer =
      static_cast<QuickAnswerText*>(quick_answer.first_answer_row[0].get());
  EXPECT_EQ(kDestRawTextPound,
            GetQuickAnswerTextForTesting(quick_answer.first_answer_row));
  EXPECT_EQ(ui::kColorLabelForegroundSecondary, answer->color_id);

  // Expectations for `StructuredResult`.
  std::unique_ptr<StructuredResult> structured_result =
      ParseInStructuredResult();
  ASSERT_TRUE(structured_result);
  ASSERT_TRUE(structured_result->unit_conversion_result);

  UnitConversionResult* unit_conversion_result =
      structured_result->unit_conversion_result.get();
  EXPECT_EQ(unit_conversion_result->source_text, kSourceRawTextKilogram);
  EXPECT_EQ(unit_conversion_result->result_text,
            base::UTF16ToASCII(answer->text));
  EXPECT_EQ(unit_conversion_result->category, kMassCategory);
  EXPECT_EQ(unit_conversion_result->source_amount, kSourceAmountKilogram);

  ASSERT_TRUE(structured_result->unit_conversion_result
                  ->source_to_dest_unit_conversion);
  UnitConversion conversion_rate =
      unit_conversion_result->source_to_dest_unit_conversion.value();
  EXPECT_EQ(conversion_rate.category(), kMassCategory);
  EXPECT_EQ(conversion_rate.source_rule().unit_name(), kKilogramName);
  EXPECT_EQ(conversion_rate.dest_rule().unit_name(), kPoundName);
  EXPECT_ROUNDED_DOUBLE_EQ(
      conversion_rate.ConvertSourceAmountToDestAmount(kSourceAmountKilogram),
      kDestAmountPound);

  EXPECT_FALSE(
      unit_conversion_result->alternative_unit_conversions_list.empty());
  std::vector<UnitConversion> alternative_conversions =
      unit_conversion_result->alternative_unit_conversions_list;
  EXPECT_EQ(2u, alternative_conversions.size());
  UnitConversion first_alt_conversion = alternative_conversions[0];
  EXPECT_EQ(first_alt_conversion.category(), kMassCategory);
  EXPECT_EQ(first_alt_conversion.source_rule().unit_name(), kKilogramName);
  EXPECT_EQ(first_alt_conversion.dest_rule().unit_name(), kOunceName);
  EXPECT_ROUNDED_DOUBLE_EQ(first_alt_conversion.ConvertSourceAmountToDestAmount(
                               kSourceAmountKilogram),
                           kDestAmountOunce);
  UnitConversion second_alt_conversion = alternative_conversions[1];
  EXPECT_EQ(second_alt_conversion.category(), kMassCategory);
  EXPECT_EQ(second_alt_conversion.source_rule().unit_name(), kKilogramName);
  EXPECT_EQ(second_alt_conversion.dest_rule().unit_name(), kGramName);
  EXPECT_ROUNDED_DOUBLE_EQ(
      second_alt_conversion.ConvertSourceAmountToDestAmount(
          kSourceAmountKilogram),
      kDestAmountGram);
}

TEST_F(UnitConversionResultParserTest,
       ParseWithResultOutOfPreferredRangeShouldReturnProperConversionResult) {
  SetCategory(kMassCategory);
  SetSourceText(kSourceRawTextKilogram);
  SetSourceAmount(kSourceAmountKilogram);
  SetDestText(kDestRawTextGram);
  SetDestAmount(kDestAmountGram);
  AddSourceUnit(CreateUnit(kKilogramName, kKilogramRateA,
                           /*rate_b=*/kInvalidRateTermValue, kMassCategory));
  AddDestUnit(CreateUnit(kGramName, kGramRateA,
                         /*rate_b=*/kInvalidRateTermValue, kMassCategory));
  AddRuleSet(BuildMassRuleSet());

  QuickAnswer quick_answer;

  EXPECT_TRUE(Parse(&quick_answer));
  EXPECT_EQ(ResultType::kUnitConversionResult, quick_answer.result_type);

  auto expected_result = BuildUnitConversionResultText(
      base::StringPrintf(kResultValueTemplate, (kKilogramRateA / kPoundRateA) *
                                                   kSourceAmountKilogram),
      GetUnitDisplayText(kPoundName));

  EXPECT_EQ(1u, quick_answer.first_answer_row.size());
  EXPECT_EQ(0u, quick_answer.title.size());
  auto* answer =
      static_cast<QuickAnswerText*>(quick_answer.first_answer_row[0].get());
  EXPECT_EQ(expected_result,
            GetQuickAnswerTextForTesting(quick_answer.first_answer_row));
  EXPECT_EQ(ui::kColorLabelForegroundSecondary, answer->color_id);

  // Expectations for `StructuredResult`.
  std::unique_ptr<StructuredResult> structured_result =
      ParseInStructuredResult();
  ASSERT_TRUE(structured_result);
  ASSERT_TRUE(structured_result->unit_conversion_result);

  UnitConversionResult* unit_conversion_result =
      structured_result->unit_conversion_result.get();
  EXPECT_EQ(unit_conversion_result->source_text, kSourceRawTextKilogram);
  EXPECT_EQ(unit_conversion_result->result_text,
            base::UTF16ToASCII(answer->text));
  EXPECT_EQ(unit_conversion_result->category, kMassCategory);
  EXPECT_EQ(unit_conversion_result->source_amount, kSourceAmountKilogram);

  ASSERT_TRUE(structured_result->unit_conversion_result
                  ->source_to_dest_unit_conversion);
  UnitConversion conversion_rate =
      unit_conversion_result->source_to_dest_unit_conversion.value();
  EXPECT_EQ(conversion_rate.category(), kMassCategory);
  EXPECT_EQ(conversion_rate.source_rule().unit_name(), kKilogramName);
  EXPECT_EQ(conversion_rate.dest_rule().unit_name(), kPoundName);
  EXPECT_ROUNDED_DOUBLE_EQ(
      conversion_rate.ConvertSourceAmountToDestAmount(kSourceAmountKilogram),
      kDestAmountPound);

  EXPECT_FALSE(
      unit_conversion_result->alternative_unit_conversions_list.empty());
  std::vector<UnitConversion> alternative_conversions =
      unit_conversion_result->alternative_unit_conversions_list;
  EXPECT_EQ(2u, alternative_conversions.size());
  UnitConversion first_alt_conversion = alternative_conversions[0];
  EXPECT_EQ(first_alt_conversion.category(), kMassCategory);
  EXPECT_EQ(first_alt_conversion.source_rule().unit_name(), kKilogramName);
  EXPECT_EQ(first_alt_conversion.dest_rule().unit_name(), kOunceName);
  EXPECT_ROUNDED_DOUBLE_EQ(first_alt_conversion.ConvertSourceAmountToDestAmount(
                               kSourceAmountKilogram),
                           kDestAmountOunce);
  UnitConversion second_alt_conversion = alternative_conversions[1];
  EXPECT_EQ(second_alt_conversion.category(), kMassCategory);
  EXPECT_EQ(second_alt_conversion.source_rule().unit_name(), kKilogramName);
  EXPECT_EQ(second_alt_conversion.dest_rule().unit_name(), kGramName);
  EXPECT_ROUNDED_DOUBLE_EQ(
      second_alt_conversion.ConvertSourceAmountToDestAmount(
          kSourceAmountKilogram),
      kDestAmountGram);
}

TEST_F(UnitConversionResultParserTest,
       ParseWithMultiVariableConversionsShouldReturnProperConversionResult) {
  SetCategory(kTemperatureCategory);
  SetSourceText(kSourceRawTextCelcius);
  SetSourceAmount(kSourceAmountCelcius);
  SetDestText(kDestRawTextFahrenheit);
  SetDestAmount(kDestAmountFahrenheit);
  AddSourceUnit(CreateUnit(kCelciusName, kCelciusRateA, kCelciusRateB,
                           kTemperatureCategory));
  AddDestUnit(CreateUnit(kFahrenheitName, kFahrenheitRateA, kFahrenheitRateB,
                         kTemperatureCategory));
  AddRuleSet(BuildTemperatureRuleSet());

  QuickAnswer quick_answer;

  EXPECT_TRUE(Parse(&quick_answer));
  EXPECT_EQ(ResultType::kUnitConversionResult, quick_answer.result_type);

  EXPECT_EQ(1u, quick_answer.first_answer_row.size());
  EXPECT_EQ(0u, quick_answer.title.size());
  auto* answer =
      static_cast<QuickAnswerText*>(quick_answer.first_answer_row[0].get());
  EXPECT_EQ(kDestRawTextFahrenheit,
            GetQuickAnswerTextForTesting(quick_answer.first_answer_row));
  EXPECT_EQ(ui::kColorLabelForegroundSecondary, answer->color_id);

  // Expectations for `StructuredResult`.
  std::unique_ptr<StructuredResult> structured_result =
      ParseInStructuredResult();
  ASSERT_TRUE(structured_result);
  ASSERT_TRUE(structured_result->unit_conversion_result);

  UnitConversionResult* unit_conversion_result =
      structured_result->unit_conversion_result.get();
  EXPECT_EQ(unit_conversion_result->source_text, kSourceRawTextCelcius);
  EXPECT_EQ(unit_conversion_result->result_text,
            base::UTF16ToASCII(answer->text));
  EXPECT_EQ(unit_conversion_result->category, kTemperatureCategory);
  EXPECT_EQ(unit_conversion_result->source_amount, kSourceAmountCelcius);

  ASSERT_TRUE(structured_result->unit_conversion_result
                  ->source_to_dest_unit_conversion);
  UnitConversion conversion_rate =
      unit_conversion_result->source_to_dest_unit_conversion.value();
  EXPECT_EQ(conversion_rate.category(), kTemperatureCategory);
  EXPECT_EQ(conversion_rate.source_rule().unit_name(), kCelciusName);
  EXPECT_EQ(conversion_rate.dest_rule().unit_name(), kFahrenheitName);
  EXPECT_ROUNDED_DOUBLE_EQ(
      conversion_rate.ConvertSourceAmountToDestAmount(kSourceAmountCelcius),
      kDestAmountFahrenheit);

  EXPECT_FALSE(
      unit_conversion_result->alternative_unit_conversions_list.empty());
  std::vector<UnitConversion> alternative_conversions =
      unit_conversion_result->alternative_unit_conversions_list;
  EXPECT_EQ(1u, alternative_conversions.size());
  UnitConversion alt_conversion = alternative_conversions[0];
  EXPECT_EQ(alt_conversion.category(), kTemperatureCategory);
  EXPECT_EQ(alt_conversion.source_rule().unit_name(), kCelciusName);
  EXPECT_EQ(alt_conversion.dest_rule().unit_name(), kKelvinName);
  EXPECT_ROUNDED_DOUBLE_EQ(
      alt_conversion.ConvertSourceAmountToDestAmount(kSourceAmountCelcius),
      kDestAmountKelvin);
}

TEST_F(UnitConversionResultParserTest,
       ParseWithNonLinearConversionsShouldReturnProperConversionResult) {
  SetCategory(kFuelEconomyCategory);
  SetSourceText(kSourceRawTextLiterPer100Kilometers);
  SetSourceAmount(kSourceAmountLiterPer100Kilometers);
  SetDestText(kDestRawTextKilometerPerLiter);
  SetDestAmount(kDestAmountKilometerPerLiter);
  AddSourceUnit(CreateUnit(kLiterPer100KilometersName,
                           /*rate_a=*/kInvalidRateTermValue,
                           /*rate_b=*/kInvalidRateTermValue,
                           kFuelEconomyCategory, kLiterPer100KilometersRateC));
  AddDestUnit(CreateUnit(kKilometerPerLiterName, kKilometerPerLiterRateA,
                         /*rate_b=*/kInvalidRateTermValue,
                         kFuelEconomyCategory));
  AddRuleSet(BuildFuelEconomyRuleSet());

  QuickAnswer quick_answer;

  EXPECT_TRUE(Parse(&quick_answer));
  EXPECT_EQ(ResultType::kUnitConversionResult, quick_answer.result_type);

  EXPECT_EQ(1u, quick_answer.first_answer_row.size());
  EXPECT_EQ(0u, quick_answer.title.size());
  auto* answer =
      static_cast<QuickAnswerText*>(quick_answer.first_answer_row[0].get());
  EXPECT_EQ(kDestRawTextKilometerPerLiter,
            GetQuickAnswerTextForTesting(quick_answer.first_answer_row));
  EXPECT_EQ(ui::kColorLabelForegroundSecondary, answer->color_id);

  // Expectations for `StructuredResult`.
  std::unique_ptr<StructuredResult> structured_result =
      ParseInStructuredResult();
  ASSERT_TRUE(structured_result);
  ASSERT_TRUE(structured_result->unit_conversion_result);

  UnitConversionResult* unit_conversion_result =
      structured_result->unit_conversion_result.get();
  EXPECT_EQ(unit_conversion_result->source_text,
            kSourceRawTextLiterPer100Kilometers);
  EXPECT_EQ(unit_conversion_result->result_text,
            base::UTF16ToASCII(answer->text));
  EXPECT_EQ(unit_conversion_result->category, kFuelEconomyCategory);
  EXPECT_EQ(unit_conversion_result->source_amount,
            kSourceAmountLiterPer100Kilometers);

  ASSERT_TRUE(structured_result->unit_conversion_result
                  ->source_to_dest_unit_conversion);
  UnitConversion conversion_rate =
      unit_conversion_result->source_to_dest_unit_conversion.value();
  EXPECT_EQ(conversion_rate.category(), kFuelEconomyCategory);
  EXPECT_EQ(conversion_rate.source_rule().unit_name(),
            kLiterPer100KilometersName);
  EXPECT_EQ(conversion_rate.dest_rule().unit_name(), kKilometerPerLiterName);
  EXPECT_ROUNDED_DOUBLE_EQ(conversion_rate.ConvertSourceAmountToDestAmount(
                               kSourceAmountLiterPer100Kilometers),
                           kDestAmountKilometerPerLiter);

  EXPECT_TRUE(
      unit_conversion_result->alternative_unit_conversions_list.empty());
}

}  // namespace quick_answers