// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "anonymous_tokens/cpp/privacy_pass/token_encodings.h"

#include <cstdint>
#include <string>
#include <vector>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
#include "anonymous_tokens/cpp/testing/utils.h"

namespace anonymous_tokens {
namespace {

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     EmptyAuthenticatorInputTest) {
  Token token;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string authenticator_input,
                                   AuthenticatorInput(token));

  std::string expected_authenticator_input_encoding =
      absl::HexStringToBytes("DA7A");

  EXPECT_EQ(authenticator_input, expected_authenticator_input_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, AuthenticatorInputTest) {
  Token token = {
      /*token_type=*/0XDA7A, /*token_key_id=*/
      absl::HexStringToBytes(
          "ca572f8982a9ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708"),
      /*nonce=*/
      absl::HexStringToBytes(
          "5f5e46604255ac6a8ae0820f5b20c236118d97d917509ccbc96b5a82ae40ebeb"),
      /*context=*/
      absl::HexStringToBytes(
          "11e15c91a7c2ad02abd66645802373db1d823bea80f08d452541fb2b62b5898b")};

  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string authenticator_input,
                                   AuthenticatorInput(token));

  std::string expected_authenticator_input_encoding = absl::HexStringToBytes(
      "DA7A5f5e46604255ac6a8ae0820f5b20c236118d97d917509ccbc96b5a82ae40ebeb11e1"
      "5c91a7c2ad02abd66645802373db1d823bea80f08d452541fb2b62b5898bca572f8982a9"
      "ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708");
  EXPECT_EQ(authenticator_input, expected_authenticator_input_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, EmptyMarshalTokenTest) {
  Token token;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_token,
                                   MarshalToken(token));
  std::string expected_token_encoding = absl::HexStringToBytes("DA7A");

  EXPECT_EQ(encoded_token, expected_token_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, MarshalTokenTest) {
  Token token = {
      /*token_type=*/0XDA7A, /*token_key_id=*/
      absl::HexStringToBytes(
          "ca572f8982a9ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708"),
      /*nonce=*/
      absl::HexStringToBytes(
          "5f5e46604255ac6a8ae0820f5b20c236118d97d917509ccbc96b5a82ae40ebeb"),
      /*context=*/
      absl::HexStringToBytes(
          "11e15c91a7c2ad02abd66645802373db1d823bea80f08d452541fb2b62b5898b"),
      /*authenticator=*/
      absl::HexStringToBytes(
          "4ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d056056"
          "86200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427"
          "bbae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087"
          "c0e881f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9"
          "321b0826d59402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6ef"
          "b54e76a5a8056f5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e"
          "36f18573f603735fac1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f"
          "01d90e0d2d784874ff000ae105483941652e")};

  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_token,
                                   MarshalToken(token));

  std::string expected_token_encoding = absl::HexStringToBytes(
      "DA7A5f5e46604255ac6a8ae0820f5b20c236118d97d917509ccbc96b5a82ae40ebeb11e1"
      "5c91a7c2ad02abd66645802373db1d823bea80f08d452541fb2b62b5898bca572f8982a9"
      "ca248a3056186322d93ca147266121ddeb5632c07f1f71cd27084ed3f2a25ec528543d9a"
      "83c850d12b3036b518fafec080df3efcd9693b944d05605686200d6500f249475737ea92"
      "46a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bbae7129b88c92ad61c08a9fe416"
      "29a642263e4857e428a706ba87659361fed38087c0e881f5e15668e0701d7edd63be98fc"
      "c7415819d466c61341de03d7e2a24181d7b9321b0826d59402a87e08514f36cc45b0f7aa"
      "c0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f5c27d01ad42119953c5987b05c"
      "9ae2ca04b12838e641b4b1aac21e36f18573f603735fac1f8f611029e4cb76c8a5cc6f2c"
      "4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000ae105483941652e");
  EXPECT_EQ(encoded_token, expected_token_encoding);

  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Token token2,
                                   UnmarshalToken(encoded_token));
  EXPECT_EQ(token.token_type, token2.token_type);
  EXPECT_EQ(token.token_key_id, token2.token_key_id);
  EXPECT_EQ(token.context, token2.context);
  EXPECT_EQ(token.nonce, token2.nonce);
  EXPECT_EQ(token.authenticator, token2.authenticator);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, UnmarshalTooShort) {
  const std::string short_token = absl::HexStringToBytes("DA7A5f5e466042");
  EXPECT_FALSE(UnmarshalToken(short_token).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, UnmarshalTooLong) {
  std::string long_token = absl::HexStringToBytes(
      "DA7A5f5e46604255ac6a8ae0820f5b20c236118d97d917509ccbc96b5a82ae40ebeb11e1"
      "5c91a7c2ad02abd66645802373db1d823bea80f08d452541fb2b62b5898bca572f8982a9"
      "ca248a3056186322d93ca147266121ddeb5632c07f1f71cd27084ed3f2a25ec528543d9a"
      "83c850d12b3036b518fafec080df3efcd9693b944d05605686200d6500f249475737ea92"
      "46a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bbae7129b88c92ad61c08a9fe416"
      "29a642263e4857e428a706ba87659361fed38087c0e881f5e15668e0701d7edd63be98fc"
      "c7415819d466c61341de03d7e2a24181d7b9321b0826d59402a87e08514f36cc45b0f7aa"
      "c0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f5c27d01ad42119953c5987b05c"
      "9ae2ca04b12838e641b4b1aac21e36f18573f603735fac1f8f611029e4cb76c8a5cc6f2c"
      "4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000ae105483941652eXXXXXXXXX");
  EXPECT_FALSE(UnmarshalToken(long_token).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, UnmarshalWrongType) {
  std::string token = absl::HexStringToBytes(
      "DA7B5f5e46604255ac6a8ae0820f5b20c236118d97d917509ccbc96b5a82ae40ebeb11e1"
      "5c91a7c2ad02abd66645802373db1d823bea80f08d452541fb2b62b5898bca572f8982a9"
      "ca248a3056186322d93ca147266121ddeb5632c07f1f71cd27084ed3f2a25ec528543d9a"
      "83c850d12b3036b518fafec080df3efcd9693b944d05605686200d6500f249475737ea92"
      "46a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bbae7129b88c92ad61c08a9fe416"
      "29a642263e4857e428a706ba87659361fed38087c0e881f5e15668e0701d7edd63be98fc"
      "c7415819d466c61341de03d7e2a24181d7b9321b0826d59402a87e08514f36cc45b0f7aa"
      "c0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f5c27d01ad42119953c5987b05c"
      "9ae2ca04b12838e641b4b1aac21e36f18573f603735fac1f8f611029e4cb76c8a5cc6f2c"
      "4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000ae105483941652e");
  EXPECT_FALSE(UnmarshalToken(token).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, EmptyExtensionTest) {
  Extension extension;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_extension,
                                   EncodeExtension(extension));

  std::string expected_extension_encoding = absl::HexStringToBytes("00010000");
  EXPECT_EQ(encoded_extension, expected_extension_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     ExtensionValueSizeOfMoreThanTwoBytes) {
  // Input string of size more than 2 bytes.
  std::string large_test_value = std::string(65536, 'a');
  // Random hex number to populate the uint16_t extension_type.
  Extension extension = {/*extension_type=*/0x5E6D,
                         /*extension_value=*/large_test_value};
  absl::StatusOr<std::string> encoded_extension = EncodeExtension(extension);

  EXPECT_EQ(encoded_extension.status().code(),
            absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(encoded_extension.status().message(),
              ::testing::HasSubstr("Failed to generate extension encoding"));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, ExtensionEncodingSuccess) {
  Extension extension = {
      // Random hex number to populate the uint16_t extension_type.
      /*extension_type=*/0x5E6D,
      // Random hex string to populate extension_value.
      /*extension_value=*/absl::HexStringToBytes(
          "46a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bbae7129b88c92ad61c08a9f"
          "e41629a642263e4857e428a706ba87659361fed38087c0e881f5e15668e0701d7edd"
          "63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d59402a87e08514f"
          "36cc45b0f7aa")};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_extension,
                                   EncodeExtension(extension));
  // The first 2 bytes of the expected_extension_encoding store the
  // extension_type. The next two bytes store the number of bytes needed for the
  // extension_value. These 4 bytes are then prefixed to the extension_value.
  std::string expected_extension_encoding = absl::HexStringToBytes(
      "5e6d006c46a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bbae7129b88c92ad61c0"
      "8a9fe41629a642263e4857e428a706ba87659361fed38087c0e881f5e15668e0701d7edd"
      "63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d59402a87e08514f36cc"
      "45b0f7aa");
  EXPECT_EQ(encoded_extension, expected_extension_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, EmptyExtensionsTest) {
  Extensions extensions;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_extensions,
                                   EncodeExtensions(extensions));

  std::string expected_extensions_encoding = absl::HexStringToBytes("0000");
  EXPECT_EQ(encoded_extensions, expected_extensions_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     ExtensionsListSizeOfMoreThanTwoBytes) {
  std::string large_test_value = std::string(65532, 'a');
  Extensions extensions;
  extensions.extensions.push_back(
      {// Random hex number to populate the uint16_t extension_type.
       /*extension_type=*/0x5E6D,
       /*extension_value=*/large_test_value});
  absl::StatusOr<std::string> encoded_extensions = EncodeExtensions(extensions);
  // The string encoding of this extensions struct will take at least 65536
  // bytes. This length is not be storable in 2 bytes.
  EXPECT_EQ(encoded_extensions.status().code(),
            absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(
      encoded_extensions.status().message(),
      ::testing::HasSubstr("Failed to generate encoded extensions list"));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     SingleExtensionInExtensionsSuccess) {
  Extensions extensions;
  extensions.extensions.push_back(Extension{
      // Random hex number to populate the uint16_t extension_type.
      /*extension_type=*/0x5E6D,
      // Random hex string to populate extension_value.
      /*extension_value=*/absl::HexStringToBytes(
          "46a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bbae7129b88c92"
          "ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e8"
          "81f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a241"
          "81d7b9321b0826d59402a87e08514f36cc45b0f7aa")});
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_extensions,
                                   EncodeExtensions(extensions));
  // The first 2 bytes of the expected_extensions_encoding store the length of
  // the rest of the string. The rest of the string is the concatenation
  // of individually encoded extensions.
  std::string expected_extensions_encoding = absl::HexStringToBytes(
      "00705e6d006c46a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bbae7129b88c92ad"
      "61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881f5e15668e0701d"
      "7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d59402a87e08514f"
      "36cc45b0f7aa");
  EXPECT_EQ(encoded_extensions, expected_extensions_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     MultipleExtensionsEncodingSuccess) {
  Extensions extensions;
  extensions.extensions.push_back(
      Extension{/*extension_type=*/0x0001,
                /*extension_value=*/absl::HexStringToBytes("01")});
  extensions.extensions.push_back(
      Extension{/*extension_type=*/0x0002,
                /*extension_value=*/absl::HexStringToBytes("0202")});
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const std::string encoded_extensions,
                                   EncodeExtensions(extensions));
  // The first 2 bytes of the expected_extensions_encoding store the length of
  // the rest of the string. The rest of the string is the concatenation
  // of individually encoded extensions.
  std::string expected_extensions_encoding =
      absl::HexStringToBytes("000b0001000101000200020202");
  EXPECT_EQ(encoded_extensions, expected_extensions_encoding);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extensions extensions2,
                                   DecodeExtensions(encoded_extensions));
  EXPECT_EQ(extensions2.extensions.size(), extensions.extensions.size());
  for (int i = 0; i < extensions.extensions.size(); ++i) {
    EXPECT_EQ(extensions2.extensions[i].extension_type,
              extensions.extensions[i].extension_type);
    EXPECT_EQ(extensions2.extensions[i].extension_value,
              extensions.extensions[i].extension_value);
  }
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     ExpirationTimestampRoundTrip) {
  ExpirationTimestamp et{.timestamp_precision = 3600, .timestamp = 1688583600};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, et.AsExtension());
  EXPECT_EQ(ext.extension_type, 0x0001);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const ExpirationTimestamp et2,
                                   ExpirationTimestamp::FromExtension(ext));
  EXPECT_EQ(et.timestamp_precision, et2.timestamp_precision);
  EXPECT_EQ(et.timestamp, et2.timestamp);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     ExpirationTimestampWrongType) {
  const Extension ext = {.extension_type = 0x0002, .extension_value = ""};
  EXPECT_FALSE(ExpirationTimestamp::FromExtension(ext).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, DecodeExtensions) {
  const std::string encoded_extensions =
      absl::HexStringToBytes("0014000100100000000000000E100000000064A5BDB0");
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extensions extensions,
                                   DecodeExtensions(encoded_extensions));
  EXPECT_EQ(extensions.extensions.size(), 1);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
      const ExpirationTimestamp et,
      ExpirationTimestamp::FromExtension(extensions.extensions[0]));
  EXPECT_EQ(et.timestamp_precision, 3600);
  EXPECT_EQ(et.timestamp, 1688583600);
  Extensions extensions2;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext2, et.AsExtension());
  extensions2.extensions.push_back(ext2);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const std::string encoded_extensions2,
                                   EncodeExtensions(extensions2));
  EXPECT_EQ(absl::BytesToHexString(encoded_extensions2),
            absl::BytesToHexString(encoded_extensions));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, DecodeTooShort) {
  const std::string encoded_extensions =
      absl::HexStringToBytes("00140001001000");
  const absl::StatusOr<Extensions> extensions =
      DecodeExtensions(encoded_extensions);
  EXPECT_FALSE(extensions.ok()) << extensions.status();
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, DecodeTooLong) {
  const std::string encoded_extensions = absl::HexStringToBytes(
      "0014000100100000000000000E100000000064A5BDB012345");
  const absl::StatusOr<Extensions> extensions =
      DecodeExtensions(encoded_extensions);
  EXPECT_FALSE(extensions.ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, GeoHintRoundTrip) {
  GeoHint gh{.geo_hint = "US,US-AL,ALABASTER"};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, gh.AsExtension());
  EXPECT_EQ(ext.extension_type, 0x0002);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const GeoHint gh2,
                                   GeoHint::FromExtension(ext));
  EXPECT_EQ(gh.geo_hint, gh2.geo_hint);
  EXPECT_EQ(gh2.country_code, "US");
  EXPECT_EQ(gh2.region, "US-AL");
  EXPECT_EQ(gh2.city, "ALABASTER");
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, GeoHintNoPostal) {
  GeoHint gh{.geo_hint = "US,US-AL,ALABASTER,FOO"};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, gh.AsExtension());
  EXPECT_FALSE(GeoHint::FromExtension(ext).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, GeoHintNoLowercase) {
  GeoHint gh{.geo_hint = "US,US-AL,Alabaster"};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, gh.AsExtension());
  EXPECT_FALSE(GeoHint::FromExtension(ext).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, GeoHintTooShort) {
  GeoHint gh{.geo_hint = "US,US-AL"};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, gh.AsExtension());
  EXPECT_FALSE(GeoHint::FromExtension(ext).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, GeoHintEmptyOk) {
  GeoHint gh{.geo_hint = "US,,"};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, gh.AsExtension());
  EXPECT_TRUE(GeoHint::FromExtension(ext).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, ServiceTypeRoundTrip) {
  ServiceType st{.service_type_id = 0x01};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, st.AsExtension());
  EXPECT_EQ(ext.extension_type, 0xF001);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const ServiceType st2,
                                   ServiceType::FromExtension(ext));
  EXPECT_EQ(st.service_type_id, st2.service_type_id);
  EXPECT_EQ(st2.service_type, "chromeipblinding");
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, WrongExtId) {
  ServiceType st{.service_type_id = 0x01};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, st.AsExtension());
  ext.extension_type = 0xF002;
  EXPECT_FALSE(ServiceType::FromExtension(ext).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, WrongServiceTypeId) {
  ServiceType st{.service_type_id = 0x02};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, st.AsExtension());
  EXPECT_EQ(ext.extension_type, 0xF001);
  EXPECT_FALSE(ServiceType::FromExtension(ext).ok());
}

TEST(AnonymousTokensDebugMode, RoundTrip) {
  DebugMode dm{.mode = DebugMode::kProd};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, dm.AsExtension());
  EXPECT_EQ(ext.extension_type, 0xF002);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const DebugMode dm2,
                                   DebugMode::FromExtension(ext));
  EXPECT_EQ(dm.mode, dm2.mode);
}

TEST(AnonymousTokensDebugMode, WrongExtId) {
  DebugMode dm{.mode = DebugMode::kProd};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, dm.AsExtension());
  ext.extension_type = 0xF003;
  EXPECT_FALSE(ServiceType::FromExtension(ext).ok());
}

TEST(AnonymousTokensDebugMode, InvalidMode) {
  DebugMode dm{.mode = DebugMode::kProd};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, dm.AsExtension());
  EXPECT_EQ(ext.extension_type, 0xF002);
  ext.extension_value = std::string("~");
  EXPECT_FALSE(DebugMode::FromExtension(ext).ok());
}

TEST(AnonymousTokensProxyLayer, RoundTripProxyA) {
  ProxyLayer pl{.layer = ProxyLayer::kProxyA};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, pl.AsExtension());
  EXPECT_EQ(ext.extension_type, 0xF003);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const ProxyLayer pl2,
                                   ProxyLayer::FromExtension(ext));
  EXPECT_EQ(pl.layer, pl2.layer);
}

TEST(AnonymousTokensProxyLayer, RoundTripProxyB) {
  ProxyLayer pl{.layer = ProxyLayer::kProxyB};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const Extension ext, pl.AsExtension());
  EXPECT_EQ(ext.extension_type, 0xF003);
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(const ProxyLayer pl2,
                                   ProxyLayer::FromExtension(ext));
  EXPECT_EQ(pl.layer, pl2.layer);
}

TEST(AnonymousTokensProxyLayer, WrongExtId) {
  ProxyLayer pl{.layer = ProxyLayer::kProxyA};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, pl.AsExtension());
  ext.extension_type = 0xF004;
  EXPECT_FALSE(ProxyLayer::FromExtension(ext).ok());
}

TEST(AnonymousTokensProxyLayer, InvalidLayer) {
  ProxyLayer pl{.layer = ProxyLayer::kProxyA};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, pl.AsExtension());
  EXPECT_EQ(ext.extension_type, 0xF003);
  ext.extension_value = std::string("~");
  EXPECT_FALSE(ProxyLayer::FromExtension(ext).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     EmptyMarshalTokenChallengeTest) {
  TokenChallenge token_challenge;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_token,
                                   MarshalTokenChallenge(token_challenge));

  std::string expected_token_encoding = absl::HexStringToBytes("DA7A0000");

  EXPECT_EQ(encoded_token, expected_token_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest, MarshalTokenChallengeTest) {
  TokenChallenge token_challenge;
  token_challenge.issuer_name = "issuer.google.com";
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_token,
                                   MarshalTokenChallenge(token_challenge));

  std::string expected_token_encoding =
      absl::HexStringToBytes("da7a00116973737565722e676f6f676c652e636f6d");

  EXPECT_EQ(encoded_token, expected_token_encoding);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     UnMarshalTokenRequestWrongTokenType) {
  std::string token_request_encoding = absl::HexStringToBytes(
      "1234124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000a"
      "e105483941652e");
  absl::StatusOr<TokenRequest> token_request =
      UnmarshalTokenRequest(token_request_encoding);

  EXPECT_EQ(token_request.status().code(), absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(token_request.status().message(),
              ::testing::HasSubstr("unsupported token type"));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     UnMarshalTokenRequestBlindedRequestTooShort) {
  std::string token_request_encoding = absl::HexStringToBytes(
      "DA7A124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000"
      "a");
  absl::StatusOr<TokenRequest> token_request =
      UnmarshalTokenRequest(token_request_encoding);

  EXPECT_EQ(token_request.status().code(), absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(token_request.status().message(),
              ::testing::HasSubstr("failed to read blinded_token_request"));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     UnMarshalTokenRequestBlindedRequestTooLong) {
  std::string token_request_encoding = absl::HexStringToBytes(
      "DA7A124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000a"
      "e105483941652ea5cc6f2c4143474e458c8d2ca8e9aa");
  absl::StatusOr<TokenRequest> token_request =
      UnmarshalTokenRequest(token_request_encoding);

  EXPECT_EQ(token_request.status().code(), absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(token_request.status().message(),
              ::testing::HasSubstr("token request had extra bytes"));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     MarshalAndUnmarshalTokenRequest) {
  TokenRequest token_request{
      .token_type = 0xDA7A,
      .truncated_token_key_id = 0x12,
      .blinded_token_request = absl::HexStringToBytes(
          "4ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d056056"
          "86200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427"
          "bbae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087"
          "c0e881f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9"
          "321b0826d59402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6ef"
          "b54e76a5a8056f5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e"
          "36f18573f603735fac1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f"
          "01d90e0d2d784874ff000ae105483941652e")};
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::string encoded_token_request,
                                   MarshalTokenRequest(token_request));

  std::string expected_token_request_encoding = absl::HexStringToBytes(
      "DA7A124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000a"
      "e105483941652e");

  EXPECT_EQ(encoded_token_request, expected_token_request_encoding);

  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
      TokenRequest decoded_token_request,
      UnmarshalTokenRequest(encoded_token_request));

  EXPECT_EQ(decoded_token_request.token_type, token_request.token_type);
  EXPECT_EQ(decoded_token_request.truncated_token_key_id,
            token_request.truncated_token_key_id);
  EXPECT_EQ(decoded_token_request.blinded_token_request,
            token_request.blinded_token_request);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     UnmarshalExtendedTokenRequestTooShort) {
  std::string extended_token_request_encoding_1 = absl::HexStringToBytes(
      "DA7A124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000a"
      "e105483941652");
  std::string extended_token_request_encoding_2 = absl::HexStringToBytes(
      "DA7A124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000a"
      "e105483941652e");

  absl::StatusOr<ExtendedTokenRequest> decoded_extended_token_request_1 =
      UnmarshalExtendedTokenRequest(extended_token_request_encoding_1);
  absl::StatusOr<ExtendedTokenRequest> decoded_extended_token_request_2 =
      UnmarshalExtendedTokenRequest(extended_token_request_encoding_2);

  EXPECT_EQ(decoded_extended_token_request_1.status().code(),
            absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(decoded_extended_token_request_1.status().message(),
              ::testing::HasSubstr("failed to read encoded_token_request"));
  EXPECT_EQ(decoded_extended_token_request_2.status().code(),
            absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(decoded_extended_token_request_2.status().message(),
              ::testing::HasSubstr("failed to read extensions."));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     UnmarshalExtendedTokenRequestTooLong) {
  std::string extended_token_request_encoding = absl::HexStringToBytes(
      "DA7A124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000a"
      "e105483941652e000b0001000101000200020202DA");

  absl::StatusOr<ExtendedTokenRequest> decoded_extended_token_request =
      UnmarshalExtendedTokenRequest(extended_token_request_encoding);

  EXPECT_EQ(decoded_extended_token_request.status().code(),
            absl::StatusCode::kInvalidArgument);
  EXPECT_THAT(decoded_extended_token_request.status().message(),
              ::testing::HasSubstr("no data after extensions is allowed"));
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     MarshalAndUnmarshalExtendedTokenRequest) {
  TokenRequest token_request{
      .token_type = 0xDA7A,
      .truncated_token_key_id = 0x12,
      .blinded_token_request = absl::HexStringToBytes(
          "4ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d056056"
          "86200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427"
          "bbae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087"
          "c0e881f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9"
          "321b0826d59402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6ef"
          "b54e76a5a8056f5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e"
          "36f18573f603735fac1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f"
          "01d90e0d2d784874ff000ae105483941652e")};
  Extensions extensions;
  extensions.extensions.push_back(
      Extension{/*extension_type=*/0x0001,
                /*extension_value=*/absl::HexStringToBytes("01")});
  extensions.extensions.push_back(
      Extension{/*extension_type=*/0x0002,
                /*extension_value=*/absl::HexStringToBytes("0202")});
  ExtendedTokenRequest extended_token_request{token_request, extensions};

  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
      std::string encoded_extended_token_request,
      MarshalExtendedTokenRequest(extended_token_request));

  std::string expected_extended_token_request_encoding = absl::HexStringToBytes(
      "DA7A124ed3f2a25ec528543d9a83c850d12b3036b518fafec080df3efcd9693b944d0560"
      "5686200d6500f249475737ea9246a70c3c2a1ff280663e46c792a8ae0d9a6877d1b427bb"
      "ae7129b88c92ad61c08a9fe41629a642263e4857e428a706ba87659361fed38087c0e881"
      "f5e15668e0701d7edd63be98fcc7415819d466c61341de03d7e2a24181d7b9321b0826d5"
      "9402a87e08514f36cc45b0f7aac0e9a6578ddb0534c8ebe528c693b6efb54e76a5a8056f"
      "5c27d01ad42119953c5987b05c9ae2ca04b12838e641b4b1aac21e36f18573f603735fac"
      "1f8f611029e4cb76c8a5cc6f2c4143474e458c8d2ca8e9a71f01d90e0d2d784874ff000a"
      "e105483941652e000b0001000101000200020202");

  EXPECT_EQ(encoded_extended_token_request,
            expected_extended_token_request_encoding);

  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
      ExtendedTokenRequest decoded_extended_token_request,
      UnmarshalExtendedTokenRequest(encoded_extended_token_request));

  EXPECT_EQ(decoded_extended_token_request.request.token_type,
            token_request.token_type);
  EXPECT_EQ(decoded_extended_token_request.request.truncated_token_key_id,
            token_request.truncated_token_key_id);
  EXPECT_EQ(decoded_extended_token_request.request.blinded_token_request,
            token_request.blinded_token_request);
  EXPECT_EQ(decoded_extended_token_request.extensions.extensions.size(),
            extensions.extensions.size());
  for (int i = 0; i < extensions.extensions.size(); ++i) {
    EXPECT_EQ(
        decoded_extended_token_request.extensions.extensions[i].extension_type,
        extensions.extensions[i].extension_type);
    EXPECT_EQ(
        decoded_extended_token_request.extensions.extensions[i].extension_value,
        extensions.extensions[i].extension_value);
  }
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     ValidateExtensionsValuesTest) {
  Extensions extensions;
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());

  ExpirationTimestamp et;
  absl::Time one_day_away = absl::Now() + absl::Hours(24);
  et.timestamp = absl::ToUnixSeconds(one_day_away);
  et.timestamp -= et.timestamp % 900;
  et.timestamp_precision = 900;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, et.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());

  GeoHint gh;
  gh.geo_hint = "US,US-AL,ALABASTER";
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(ext, gh.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());

  ServiceType svc;
  svc.service_type_id = ServiceType::kChromeIpBlinding;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(ext, svc.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());

  DebugMode debug;
  debug.mode = DebugMode::kDebug;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(ext, debug.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());

  ProxyLayer proxy_layer;
  proxy_layer.layer = ProxyLayer::kProxyA;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(ext, proxy_layer.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     NotRoundedExpirationExtensionValidationTest) {
  Extensions extensions;
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());

  ExpirationTimestamp et;
  absl::Time one_day_away = absl::Now() + absl::Hours(24);
  et.timestamp = absl::ToUnixSeconds(one_day_away);
  et.timestamp -= et.timestamp % 900;
  et.timestamp += 17;
  et.timestamp_precision = 900;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, et.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_EQ(ValidateExtensionsValues(extensions, absl::Now()).code(),
            absl::StatusCode::kInvalidArgument);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     BadPrecisionExpirationExtensionValidationTest) {
  Extensions extensions;
  EXPECT_TRUE(ValidateExtensionsValues(extensions, absl::Now()).ok());

  ExpirationTimestamp et;
  absl::Time one_day_away = absl::Now() + absl::Hours(24);
  et.timestamp = absl::ToUnixSeconds(one_day_away);
  et.timestamp -= et.timestamp % 2;
  et.timestamp_precision = 2;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, et.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_EQ(ValidateExtensionsValues(extensions, absl::Now()).code(),
            absl::StatusCode::kInvalidArgument);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     MissingCountryGeoHintExtensionValidationTest) {
  Extensions extensions;
  GeoHint gh;
  gh.geo_hint = "US-AL,ALABASTER";
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, gh.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_EQ(ValidateExtensionsValues(extensions, absl::Now()).code(),
              absl::StatusCode::kInvalidArgument);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     CountryLowercaseGeoHintExtensionValidationTest) {
  Extensions extensions;
  GeoHint gh;
  gh.geo_hint = "us,US-AL,ALABASTER";
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, gh.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_EQ(ValidateExtensionsValues(extensions, absl::Now()).code(),
              absl::StatusCode::kInvalidArgument);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     NotCountryCodeGeoHintExtensionValidationTest) {
  Extensions extensions;
  GeoHint gh;
  gh.geo_hint = "USA,US-AL,ALABASTER";
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, gh.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_EQ(ValidateExtensionsValues(extensions, absl::Now()).code(),
              absl::StatusCode::kInvalidArgument);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     RegionLowercaseGeoHintExtensionValidationTest) {
  Extensions extensions;
  GeoHint gh;
  gh.geo_hint = "US,US-al,ALABASTER";
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, gh.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_EQ(ValidateExtensionsValues(extensions, absl::Now()).code(),
              absl::StatusCode::kInvalidArgument);
}

TEST(AnonymousTokensPrivacyPassTokenEncodingsTest,
     ValidateExtensionsOrderAndValuesTest) {
  Extensions extensions;
  std::vector<uint16_t> expected_types;
  EXPECT_TRUE(ValidateExtensionsOrderAndValues(
                  extensions, absl::MakeSpan(expected_types), absl::Now())
                  .ok());

  ExpirationTimestamp et;
  absl::Time one_day_away = absl::Now() + absl::Hours(24);
  et.timestamp = absl::ToUnixSeconds(one_day_away);
  et.timestamp -= et.timestamp % 900;
  et.timestamp_precision = 900;
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(Extension ext, et.AsExtension());
  extensions.extensions.push_back(ext);
  expected_types.push_back(0x0001);
  EXPECT_TRUE(ValidateExtensionsOrderAndValues(
                  extensions, absl::MakeSpan(expected_types), absl::Now())
                  .ok());

  expected_types.push_back(0x0002);
  EXPECT_FALSE(ValidateExtensionsOrderAndValues(
                   extensions, absl::MakeSpan(expected_types), absl::Now())
                   .ok());

  GeoHint gh;
  gh.geo_hint = "US,US-AL,ALABASTER";
  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(ext, gh.AsExtension());
  extensions.extensions.push_back(ext);
  EXPECT_TRUE(ValidateExtensionsOrderAndValues(
                  extensions, absl::MakeSpan(expected_types), absl::Now())
                  .ok());

  expected_types.clear();
  EXPECT_FALSE(ValidateExtensionsOrderAndValues(
                   extensions, absl::MakeSpan(expected_types), absl::Now())
                   .ok());

  expected_types.push_back(0x0002);
  expected_types.push_back(0x0001);
  EXPECT_FALSE(ValidateExtensionsOrderAndValues(
                   extensions, absl::MakeSpan(expected_types), absl::Now())
                   .ok());
}

}  // namespace
}  // namespace anonymous_tokens
