// Copyright (c) 2009-2021, Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Google LLC nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "protos/protos.h"
#include "protos/repeated_field.h"
#include "protos/repeated_field_iterator.h"
#include "protos_generator/tests/child_model.upb.proto.h"
#include "protos_generator/tests/no_package.upb.proto.h"
#include "protos_generator/tests/test_model.upb.proto.h"
#include "upb/upb.hpp"

using ::protos_generator::test::protos::ChildModel1;
using ::protos_generator::test::protos::other_ext;
using ::protos_generator::test::protos::RED;
using ::protos_generator::test::protos::TestEnum;
using ::protos_generator::test::protos::TestModel;
using ::protos_generator::test::protos::TestModel_Category;
using ::protos_generator::test::protos::TestModel_Category_IMAGES;
using ::protos_generator::test::protos::TestModel_Category_NEWS;
using ::protos_generator::test::protos::TestModel_Category_VIDEO;
using ::protos_generator::test::protos::theme;
using ::protos_generator::test::protos::ThemeExtension;
using ::testing::ElementsAre;

TEST(CppGeneratedCode, Constructor) { TestModel test_model; }

TEST(CppGeneratedCode, MessageEnum) { EXPECT_EQ(5, TestModel_Category_IMAGES); }

TEST(CppGeneratedCode, ImportedEnum) { EXPECT_EQ(3, TestEnum::DEVICE_MONITOR); }

TEST(CppGeneratedCode, Enum) { EXPECT_EQ(1, RED); }

TEST(CppGeneratedCode, EnumNoPackage) { EXPECT_EQ(1, ::protos_CELSIUS); }

TEST(CppGeneratedCode, MessageEnumType) {
  TestModel_Category category1 = TestModel_Category_IMAGES;
  TestModel::Category category2 = TestModel::IMAGES;
  EXPECT_EQ(category1, category2);
}

TEST(CppGeneratedCode, MessageEnumValue) {
  EXPECT_EQ(TestModel_Category_IMAGES, TestModel::IMAGES);
}

TEST(CppGeneratedCode, ArenaConstructor) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(false, testModel.has_b1());
}

TEST(CppGeneratedCode, Booleans) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_FALSE(testModel.b1());
  testModel.set_b1(true);
  EXPECT_TRUE(testModel.b1());
  testModel.set_b1(false);
  EXPECT_FALSE(testModel.b1());
  testModel.set_b1(true);
  EXPECT_TRUE(testModel.b1());
  testModel.clear_b1();
  EXPECT_FALSE(testModel.has_b1());
}

TEST(CppGeneratedCode, ScalarInt32) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);
  // Test int32 defaults.
  EXPECT_EQ(testModel.value(), 0);
  EXPECT_FALSE(testModel.has_value());
  // Floating point defautls.
  EXPECT_EQ(std::numeric_limits<float>::infinity(),
            testModel.float_value_with_default());
  EXPECT_EQ(-std::numeric_limits<double>::infinity(),
            testModel.double_value_with_default());

  // Set value.
  testModel.set_value(5);
  EXPECT_TRUE(testModel.has_value());
  EXPECT_EQ(testModel.value(), 5);
  // Change value.
  testModel.set_value(10);
  EXPECT_TRUE(testModel.has_value());
  EXPECT_EQ(testModel.value(), 10);
  // Clear value.
  testModel.clear_value();
  EXPECT_FALSE(testModel.has_value());
  EXPECT_EQ(testModel.value(), 0);
}

const char kTestStr1[] = "abcdefg";
const char kTestStr2[] = "just another test string";

TEST(CppGeneratedCode, Strings) {
  TestModel testModel;
  testModel.set_str1(kTestStr1);
  testModel.set_str2(kTestStr2);
  EXPECT_EQ(testModel.str1(), kTestStr1);
  EXPECT_EQ(testModel.str2(), kTestStr2);
  EXPECT_TRUE(testModel.has_str1());
  EXPECT_TRUE(testModel.has_str2());

  testModel.clear_str1();
  EXPECT_FALSE(testModel.has_str1());
  EXPECT_TRUE(testModel.has_str2());
}

TEST(CppGeneratedCode, ScalarUInt32) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);
  // Test defaults.
  EXPECT_EQ(testModel.optional_uint32(), 0);
  EXPECT_FALSE(testModel.has_optional_uint32());
  // Set value.
  testModel.set_optional_uint32(0xA0001000);
  EXPECT_TRUE(testModel.has_optional_uint32());
  EXPECT_EQ(testModel.optional_uint32(), 0xA0001000);
  // Change value.
  testModel.set_optional_uint32(0x70002000);
  EXPECT_TRUE(testModel.has_optional_uint32());
  EXPECT_EQ(testModel.optional_uint32(), 0x70002000);
  // Clear value.
  testModel.clear_optional_uint32();
  EXPECT_FALSE(testModel.has_optional_uint32());
  EXPECT_EQ(testModel.optional_uint32(), 0);
}

TEST(CppGeneratedCode, ScalarInt64) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);
  // Test defaults.
  EXPECT_EQ(testModel.optional_int64(), 0);
  EXPECT_FALSE(testModel.has_optional_int64());
  // Set value.
  testModel.set_optional_int64(0xFF00CCDDA0001000);
  EXPECT_TRUE(testModel.has_optional_int64());
  EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000);
  // Change value.
  testModel.set_optional_int64(0xFF00CCDD70002000);
  EXPECT_TRUE(testModel.has_optional_int64());
  EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDD70002000);
  // Clear value.
  testModel.clear_optional_int64();
  EXPECT_FALSE(testModel.has_optional_int64());
  EXPECT_EQ(testModel.optional_int64(), 0);
  // Set after clear.
  testModel.set_optional_int64(0xFF00CCDDA0001000);
  EXPECT_TRUE(testModel.has_optional_int64());
  EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000);
}

TEST(CppGeneratedCode, ScalarFloat) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);
  // Test defaults.
  EXPECT_EQ(testModel.optional_float(), 0.0f);
  EXPECT_FALSE(testModel.has_optional_float());
  EXPECT_EQ(std::numeric_limits<float>::infinity(),
            testModel.float_value_with_default());
  EXPECT_EQ(-std::numeric_limits<double>::infinity(),
            testModel.double_value_with_default());
  // Set value.
  testModel.set_optional_float(3.14159265f);
  EXPECT_TRUE(testModel.has_optional_float());
  EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f);
  // Change value.
  testModel.set_optional_float(-2.0f);
  EXPECT_TRUE(testModel.has_optional_float());
  EXPECT_NEAR(testModel.optional_float(), -2, 1e-9f);
  // Clear value.
  testModel.clear_optional_float();
  EXPECT_FALSE(testModel.has_optional_float());
  EXPECT_EQ(testModel.optional_float(), 0.0f);
  // Set after clear.
  testModel.set_optional_float(3.14159265f);
  EXPECT_TRUE(testModel.has_optional_float());
  EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f);
}

TEST(CppGeneratedCode, ScalarDouble) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);
  // Test defaults.
  EXPECT_EQ(testModel.optional_double(), 0.0);
  EXPECT_FALSE(testModel.has_optional_double());
  // Set value.
  testModel.set_optional_double(3.141592653589793);
  EXPECT_TRUE(testModel.has_optional_double());
  EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f);
  // Change value.
  testModel.set_optional_double(-1.0);
  EXPECT_TRUE(testModel.has_optional_double());
  EXPECT_NEAR(testModel.optional_double(), -1.0, 1e-16f);
  // Clear value.
  testModel.clear_optional_double();
  EXPECT_FALSE(testModel.has_optional_double());
  EXPECT_EQ(testModel.optional_double(), 0.0f);
  // Set after clear.
  testModel.set_optional_double(3.141592653589793);
  EXPECT_TRUE(testModel.has_optional_double());
  EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f);
}

TEST(CppGeneratedCode, Enums) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);

  // Check enum default value.
  EXPECT_EQ(TestModel_Category_IMAGES, 5);

  // Test defaults.
  EXPECT_FALSE(testModel.has_category());
  EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES);
  // Set value.
  testModel.set_category(TestModel_Category_NEWS);
  EXPECT_TRUE(testModel.has_category());
  EXPECT_EQ(testModel.category(), TestModel_Category_NEWS);
  // Change value.
  testModel.set_category(TestModel_Category_VIDEO);
  EXPECT_TRUE(testModel.has_category());
  EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO);
  // Clear value.
  testModel.clear_category();
  EXPECT_FALSE(testModel.has_category());
  EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES);
  // Set after clear.
  testModel.set_category(TestModel_Category_VIDEO);
  EXPECT_TRUE(testModel.has_category());
  EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO);
}

TEST(CppGeneratedCode, FieldWithDefaultValue) {
  ::protos::Arena arena;
  auto testModel = ::protos::CreateMessage<TestModel>(arena);

  EXPECT_FALSE(testModel.has_int_value_with_default());
  EXPECT_EQ(testModel.int_value_with_default(), 65);
  testModel.set_int_value_with_default(10);
  EXPECT_EQ(testModel.int_value_with_default(), 10);

  EXPECT_FALSE(testModel.has_string_value_with_default());
  EXPECT_EQ(testModel.string_value_with_default(), "hello");
  testModel.set_string_value_with_default("new string");
  EXPECT_EQ(testModel.string_value_with_default(), "new string");
}

TEST(CppGeneratedCode, OneOfFields) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);

  EXPECT_FALSE(test_model.has_oneof_member1());
  EXPECT_FALSE(test_model.has_oneof_member2());
  EXPECT_EQ(TestModel::CHILD_ONEOF1_NOT_SET, test_model.child_oneof1_case());

  test_model.set_oneof_member1("one of string");
  EXPECT_TRUE(test_model.has_oneof_member1());
  EXPECT_FALSE(test_model.has_oneof_member2());
  EXPECT_EQ(test_model.oneof_member1(), "one of string");
  EXPECT_EQ(TestModel::kOneofMember1, test_model.child_oneof1_case());

  test_model.set_oneof_member2(true);
  EXPECT_FALSE(test_model.has_oneof_member1());
  EXPECT_TRUE(test_model.has_oneof_member2());
  EXPECT_EQ(test_model.oneof_member2(), true);
  EXPECT_EQ(TestModel::kOneofMember2, test_model.child_oneof1_case());

  test_model.clear_oneof_member2();
  EXPECT_FALSE(test_model.has_oneof_member1());
  EXPECT_FALSE(test_model.has_oneof_member2());
  EXPECT_EQ(test_model.oneof_member1(), "");
  EXPECT_EQ(test_model.oneof_member2(), false);
  EXPECT_EQ(TestModel::CHILD_ONEOF1_NOT_SET, test_model.child_oneof1_case());
}

TEST(CppGeneratedCode, Messages) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(false, test_model.has_child_model_1());
  auto child_model = test_model.child_model_1();
  EXPECT_EQ(false, child_model->has_child_b1());
  EXPECT_EQ(false, child_model->child_b1());
  auto mutable_child = test_model.mutable_child_model_1();
  mutable_child->set_child_b1(true);
  EXPECT_EQ(true, mutable_child->has_child_b1());
  EXPECT_EQ(true, mutable_child->child_b1());
  // The View should not change due to mutation since it
  // is default_instance.
  EXPECT_EQ(false, child_model->has_child_b1());
  // Readonly View should now show change.
  child_model = test_model.child_model_1();
  EXPECT_EQ(true, child_model->has_child_b1());
  EXPECT_EQ(true, child_model->child_b1());
  // Clear message field.
  EXPECT_EQ(true, test_model.has_child_model_1());
  test_model.clear_child_model_1();
  EXPECT_EQ(false, test_model.has_child_model_1());
}

TEST(CppGeneratedCode, NestedMessages) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  auto nested_child = test_model.nested_child_1();
  EXPECT_EQ(0, nested_child->nested_child_name().size());
  auto mutable_nested_child = test_model.mutable_nested_child_1();
  EXPECT_EQ(false, mutable_nested_child->has_nested_child_name());
  mutable_nested_child->set_nested_child_name(kTestStr1);
  EXPECT_EQ(true, mutable_nested_child->has_nested_child_name());
}

TEST(CppGeneratedCode, RepeatedMessages) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.child_models_size());
  // Should be able to clear repeated field when empty.
  test_model.mutable_child_models()->clear();
  EXPECT_EQ(0, test_model.child_models_size());
  // Add 2 children.
  auto new_child = test_model.add_child_models();
  EXPECT_EQ(true, new_child.ok());
  new_child.value()->set_child_str1(kTestStr1);
  new_child = test_model.add_child_models();
  EXPECT_EQ(true, new_child.ok());
  new_child.value()->set_child_str1(kTestStr2);
  EXPECT_EQ(2, test_model.child_models_size());
  // Mutable access.
  auto mutable_first = test_model.mutable_child_models(0);
  EXPECT_EQ(mutable_first->child_str1(), kTestStr1);
  mutable_first->set_child_str1("change1");
  auto mutable_second = test_model.mutable_child_models(1);
  EXPECT_EQ(mutable_second->child_str1(), kTestStr2);
  mutable_second->set_child_str1("change2");
  // Check mutations using views.
  auto view_first = test_model.child_models(0);
  EXPECT_EQ(view_first->child_str1(), "change1");
  auto view_second = test_model.child_models(1);
  EXPECT_EQ(view_second->child_str1(), "change2");
}

TEST(CppGeneratedCode, RepeatedScalar) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.value_array_size());
  // Should be able to clear repeated field when empty.
  test_model.mutable_value_array()->clear();
  EXPECT_EQ(0, test_model.value_array_size());
  // Add 2 children.
  EXPECT_EQ(true, test_model.add_value_array(5));
  EXPECT_EQ(true, test_model.add_value_array(6));
  EXPECT_EQ(2, test_model.value_array_size());
  EXPECT_EQ(5, test_model.value_array(0));
  EXPECT_EQ(6, test_model.value_array(1));
  EXPECT_EQ(true, test_model.resize_value_array(3));
  EXPECT_EQ(3, test_model.value_array_size());
  test_model.set_value_array(2, 7);
  EXPECT_EQ(5, test_model.value_array(0));
  EXPECT_EQ(6, test_model.value_array(1));
  EXPECT_EQ(7, test_model.value_array(2));
}

TEST(CppGeneratedCode, RepeatedFieldClear) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  test_model.mutable_value_array()->push_back(5);
  test_model.mutable_value_array()->push_back(16);
  test_model.mutable_value_array()->push_back(27);
  ASSERT_EQ(test_model.mutable_value_array()->size(), 3);
  test_model.mutable_value_array()->clear();
  EXPECT_EQ(test_model.mutable_value_array()->size(), 0);
}

TEST(CppGeneratedCode, RepeatedFieldProxyForScalars) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.value_array().size());
  EXPECT_EQ(0, test_model.mutable_value_array()->size());

  test_model.mutable_value_array()->push_back(5);
  test_model.mutable_value_array()->push_back(16);
  test_model.mutable_value_array()->push_back(27);

  ASSERT_EQ(test_model.mutable_value_array()->size(), 3);
  EXPECT_EQ((*test_model.mutable_value_array())[0], 5);
  EXPECT_EQ((*test_model.mutable_value_array())[1], 16);
  EXPECT_EQ((*test_model.mutable_value_array())[2], 27);

  const auto value_array = test_model.value_array();
  ASSERT_EQ(value_array.size(), 3);
  EXPECT_EQ(value_array[0], 5);
  EXPECT_EQ(value_array[1], 16);
  EXPECT_EQ(value_array[2], 27);

  EXPECT_THAT(value_array, ElementsAre(5, 16, 27));

  EXPECT_THAT(std::vector(value_array.begin(), value_array.end()),
              ElementsAre(5, 16, 27));
  EXPECT_THAT(std::vector(value_array.cbegin(), value_array.cend()),
              ElementsAre(5, 16, 27));
  EXPECT_THAT(std::vector(value_array.rbegin(), value_array.rend()),
              ElementsAre(27, 16, 5));
  EXPECT_THAT(std::vector(value_array.crbegin(), value_array.crend()),
              ElementsAre(27, 16, 5));
}

TEST(CppGeneratedCode, RepeatedScalarIterator) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  test_model.mutable_value_array()->push_back(5);
  test_model.mutable_value_array()->push_back(16);
  test_model.mutable_value_array()->push_back(27);
  int sum = 0;
  // Access by value.
  const ::protos::RepeatedField<int32_t>::CProxy rep1 =
      test_model.value_array();
  for (auto i : rep1) {
    sum += i;
  }
  EXPECT_EQ(sum, 5 + 16 + 27);
  // Access by const reference.
  sum = 0;
  for (const int& i : *test_model.mutable_value_array()) {
    sum += i;
  }
  EXPECT_EQ(sum, 5 + 16 + 27);
  // Access by forwarding reference.
  sum = 0;
  for (auto&& i : *test_model.mutable_value_array()) {
    sum += i;
  }
  EXPECT_EQ(sum, 5 + 16 + 27);
  // Test iterator operators.
  auto begin = test_model.value_array().begin();
  auto end = test_model.value_array().end();
  sum = 0;
  for (auto it = begin; it != end; ++it) {
    sum += *it;
  }
  EXPECT_EQ(sum, 5 + 16 + 27);
  auto it = begin;
  ++it;
  EXPECT_TRUE(begin < it);
  EXPECT_TRUE(begin <= it);
  it = end;
  EXPECT_TRUE(it == end);
  EXPECT_TRUE(it > begin);
  EXPECT_TRUE(it >= begin);
  EXPECT_TRUE(it != begin);
  // difference type
  it = end;
  --it;
  --it;
  EXPECT_EQ(end - it, 2);
  it = begin;
  EXPECT_EQ(it[0], 5);
  EXPECT_EQ(it[1], 16);
  EXPECT_EQ(it[2], 27);
  // ValueProxy.
  sum = 0;
  for (::protos::RepeatedField<int32_t>::ValueCProxy c :
       test_model.value_array()) {
    sum += c;
  }
  EXPECT_EQ(sum, 5 + 16 + 27);
  sum = 0;
  for (::protos::RepeatedField<int32_t>::ValueProxy c :
       *test_model.mutable_value_array()) {
    sum += c;
  }
  EXPECT_EQ(sum, 5 + 16 + 27);
}

TEST(CppGeneratedCode, RepeatedFieldProxyForStrings) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.repeated_string().size());
  EXPECT_EQ(0, test_model.mutable_repeated_string()->size());

  test_model.mutable_repeated_string()->push_back("a");
  test_model.mutable_repeated_string()->push_back("b");
  test_model.mutable_repeated_string()->push_back("c");

  ASSERT_EQ(test_model.repeated_string().size(), 3);
  EXPECT_EQ(test_model.repeated_string()[0], "a");
  EXPECT_EQ(test_model.repeated_string()[1], "b");
  EXPECT_EQ(test_model.repeated_string()[2], "c");

  EXPECT_THAT(test_model.repeated_string(), ElementsAre("a", "b", "c"));
  EXPECT_THAT(*test_model.mutable_repeated_string(),
              ElementsAre("a", "b", "c"));

  ASSERT_EQ(test_model.mutable_repeated_string()->size(), 3);
  EXPECT_EQ((*test_model.mutable_repeated_string())[0], "a");
  EXPECT_EQ((*test_model.mutable_repeated_string())[1], "b");
  EXPECT_EQ((*test_model.mutable_repeated_string())[2], "c");

  // The const accessor can't be used to modify the element
  EXPECT_FALSE((std::is_assignable<decltype(test_model.repeated_string()[1]),
                                   absl::string_view>::value));
  // But the mutable one is fine.
  (*test_model.mutable_repeated_string())[1] = "other";
  EXPECT_THAT(test_model.repeated_string(), ElementsAre("a", "other", "c"));

  test_model.mutable_repeated_string()->clear();
  EXPECT_EQ(test_model.mutable_repeated_string()->size(), 0);
}

TEST(CppGeneratedCode, RepeatedFieldProxyForMessages) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.child_models().size());
  ChildModel1 child1;
  child1.set_child_str1(kTestStr1);
  test_model.mutable_child_models()->push_back(child1);
  ChildModel1 child2;
  child2.set_child_str1(kTestStr2);
  test_model.mutable_child_models()->push_back(std::move(child2));
  EXPECT_EQ(test_model.child_models().size(), 2);
  EXPECT_EQ(test_model.child_models()[0].child_str1(), kTestStr1);
  EXPECT_EQ(test_model.child_models()[1].child_str1(), kTestStr2);
  EXPECT_EQ((*test_model.mutable_child_models())[0].child_str1(), kTestStr1);
  EXPECT_EQ((*test_model.mutable_child_models())[1].child_str1(), kTestStr2);
  (*test_model.mutable_child_models())[0].set_child_str1("change1");
  EXPECT_EQ((*test_model.mutable_child_models())[0].child_str1(), "change1");
  test_model.mutable_child_models()->clear();
  EXPECT_EQ(test_model.mutable_child_models()->size(), 0);
}

TEST(CppGeneratedCode, RepeatedFieldProxyForMessagesIndexOperator) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.child_models().size());
  ChildModel1 child1;
  child1.set_child_str1(kTestStr1);
  test_model.mutable_child_models()->push_back(child1);
  ChildModel1 child2;

  child2.set_child_str1(kTestStr2);
  test_model.mutable_child_models()->push_back(std::move(child2));
  ASSERT_EQ(test_model.child_models().size(), 2);

  // test_model.child_models()[0].set_child_str1("change1");
  (*test_model.mutable_child_models())[0].set_child_str1("change1");
  EXPECT_EQ((*test_model.mutable_child_models())[0].child_str1(), "change1");
}

TEST(CppGeneratedCode, RepeatedStrings) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.repeated_string_size());
  // Should be able to clear repeated field when empty.
  test_model.mutable_repeated_string()->clear();
  EXPECT_EQ(0, test_model.repeated_string_size());
  // Add 2 children.
  EXPECT_EQ(true, test_model.add_repeated_string("Hello"));
  EXPECT_EQ(true, test_model.add_repeated_string("World"));
  EXPECT_EQ(2, test_model.repeated_string_size());
  EXPECT_EQ("Hello", test_model.repeated_string(0));
  EXPECT_EQ("World", test_model.repeated_string(1));
  EXPECT_EQ(true, test_model.resize_repeated_string(3));
  EXPECT_EQ(3, test_model.repeated_string_size());
  test_model.set_repeated_string(2, "Test");
  EXPECT_EQ("Hello", test_model.repeated_string(0));
  EXPECT_EQ("World", test_model.repeated_string(1));
  EXPECT_EQ("Test", test_model.repeated_string(2));
}

TEST(CppGeneratedCode, MessageMapInt32KeyMessageValue) {
  const int key_test_value = 3;
  ::protos::Arena arena;
  ::protos::Arena child_arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.child_map_size());
  test_model.clear_child_map();
  EXPECT_EQ(0, test_model.child_map_size());
  auto child_model1 = ::protos::CreateMessage<ChildModel1>(child_arena);
  child_model1.set_child_str1("abc");
  test_model.set_child_map(key_test_value, child_model1);
  auto map_result = test_model.get_child_map(key_test_value);
  EXPECT_EQ(true, map_result.ok());
  EXPECT_EQ("abc", map_result.value()->child_str1());
  // Now mutate original child model to verify that value semantics are
  // preserved.
  child_model1.set_child_str1("abc V2");
  EXPECT_EQ("abc", map_result.value()->child_str1());
  test_model.delete_child_map(key_test_value);
  auto map_result_after_delete = test_model.get_child_map(key_test_value);
  EXPECT_EQ(false, map_result_after_delete.ok());
}

TEST(CppGeneratedCode, MessageMapStringKeyAndStringValue) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.str_to_str_map_size());
  test_model.clear_str_to_str_map();
  EXPECT_EQ(0, test_model.str_to_str_map_size());
  test_model.set_str_to_str_map("first", "abc");
  test_model.set_str_to_str_map("second", "def");
  auto result = test_model.get_str_to_str_map("second");
  EXPECT_EQ(true, result.ok());
  EXPECT_EQ("def", result.value());
  test_model.delete_str_to_str_map("first");
  auto result_after_delete = test_model.get_str_to_str_map("first");
  EXPECT_EQ(false, result_after_delete.ok());
}

TEST(CppGeneratedCode, MessageMapStringKeyAndInt32Value) {
  ::protos::Arena arena;
  auto test_model = ::protos::CreateMessage<TestModel>(arena);
  EXPECT_EQ(0, test_model.str_to_int_map_size());
  test_model.clear_str_to_int_map();
  EXPECT_EQ(0, test_model.str_to_int_map_size());
  test_model.set_str_to_int_map("first", 10);
  EXPECT_EQ(1, test_model.str_to_int_map_size());
  test_model.set_str_to_int_map("second", 20);
  EXPECT_EQ(2, test_model.str_to_int_map_size());
  auto result = test_model.get_str_to_int_map("second");
  EXPECT_EQ(true, result.ok());
  EXPECT_EQ(20, result.value());
  test_model.delete_str_to_int_map("first");
  auto result_after_delete = test_model.get_str_to_int_map("first");
  EXPECT_EQ(false, result_after_delete.ok());
}

TEST(CppGeneratedCode, HasExtension) {
  TestModel model;
  EXPECT_EQ(false, ::protos::HasExtension(&model, theme));
}

TEST(CppGeneratedCode, HasExtensionPtr) {
  TestModel model;
  EXPECT_EQ(false, ::protos::HasExtension(model.recursive_child(), theme));
}

TEST(CppGeneratedCode, ClearExtensionWithEmptyExtension) {
  TestModel model;
  EXPECT_EQ(false, ::protos::HasExtension(&model, theme));
  ::protos::ClearExtension(&model, theme);
  EXPECT_EQ(false, ::protos::HasExtension(&model, theme));
}

TEST(CppGeneratedCode, ClearExtensionWithEmptyExtensionPtr) {
  TestModel model;
  ::protos::Ptr<TestModel> recursive_child = model.mutable_recursive_child();
  ::protos::ClearExtension(recursive_child, theme);
  EXPECT_EQ(false, ::protos::HasExtension(recursive_child, theme));
}

TEST(CppGeneratedCode, SetExtension) {
  TestModel model;
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  EXPECT_EQ(false, ::protos::HasExtension(&model, theme));
  EXPECT_EQ(true, ::protos::SetExtension(&model, theme, extension1).ok());
  EXPECT_EQ(true, ::protos::HasExtension(&model, theme));
}

TEST(CppGeneratedCode, SetExtensionOnMutableChild) {
  TestModel model;
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  EXPECT_EQ(false,
            ::protos::HasExtension(model.mutable_recursive_child(), theme));
  EXPECT_EQ(true, ::protos::SetExtension(model.mutable_recursive_child(), theme,
                                         extension1)
                      .ok());
  EXPECT_EQ(true,
            ::protos::HasExtension(model.mutable_recursive_child(), theme));
}

TEST(CppGeneratedCode, GetExtension) {
  TestModel model;
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  EXPECT_EQ(false, ::protos::HasExtension(&model, theme));
  EXPECT_EQ(true, ::protos::SetExtension(&model, theme, extension1).ok());
  EXPECT_EQ("Hello World",
            ::protos::GetExtension(&model, theme).value()->ext_name());
}

TEST(CppGeneratedCode, GetExtensionOnMutableChild) {
  TestModel model;
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  ::protos::Ptr<TestModel> mutable_recursive_child =
      model.mutable_recursive_child();
  EXPECT_EQ(false, ::protos::HasExtension(mutable_recursive_child, theme));
  EXPECT_EQ(
      true,
      ::protos::SetExtension(mutable_recursive_child, theme, extension1).ok());
  EXPECT_EQ("Hello World",
            ::protos::GetExtension(mutable_recursive_child, theme)
                .value()
                ->ext_name());
}

TEST(CppGeneratedCode, GetExtensionOnImmutableChild) {
  TestModel model;
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  ::protos::Ptr<TestModel> mutable_recursive_child =
      model.mutable_recursive_child();
  EXPECT_EQ(false, ::protos::HasExtension(mutable_recursive_child, theme));
  EXPECT_EQ(
      true,
      ::protos::SetExtension(mutable_recursive_child, theme, extension1).ok());
  ::protos::Ptr<const TestModel> recursive_child = model.recursive_child();
  EXPECT_EQ("Hello World",
            ::protos::GetExtension(recursive_child, theme).value()->ext_name());
}

TEST(CppGeneratedCode, SerializeUsingArena) {
  TestModel model;
  model.set_str1("Hello World");
  ::upb::Arena arena;
  absl::StatusOr<absl::string_view> bytes = ::protos::Serialize(&model, arena);
  EXPECT_EQ(true, bytes.ok());
  TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value();
  EXPECT_EQ("Hello World", parsed_model.str1());
}

TEST(CppGeneratedCode, SerializeProxyUsingArena) {
  ::upb::Arena message_arena;
  TestModel::Proxy model_proxy =
      ::protos::CreateMessage<TestModel>(message_arena);
  model_proxy.set_str1("Hello World");
  ::upb::Arena arena;
  absl::StatusOr<absl::string_view> bytes =
      ::protos::Serialize(&model_proxy, arena);
  EXPECT_EQ(true, bytes.ok());
  TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value();
  EXPECT_EQ("Hello World", parsed_model.str1());
}

TEST(CppGeneratedCode, SerializeNestedMessageUsingArena) {
  TestModel model;
  model.mutable_recursive_child()->set_str1("Hello World");
  ::upb::Arena arena;
  ::protos::Ptr<const TestModel> child = model.recursive_child();
  absl::StatusOr<absl::string_view> bytes = ::protos::Serialize(child, arena);
  EXPECT_EQ(true, bytes.ok());
  TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value();
  EXPECT_EQ("Hello World", parsed_model.str1());
}

TEST(CppGeneratedCode, Parse) {
  TestModel model;
  model.set_str1("Test123");
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  EXPECT_EQ(true, ::protos::SetExtension(&model, theme, extension1).ok());
  ::upb::Arena arena;
  auto bytes = ::protos::Serialize(&model, arena);
  EXPECT_EQ(true, bytes.ok());
  TestModel parsed_model = ::protos::Parse<TestModel>(bytes.value()).value();
  EXPECT_EQ("Test123", parsed_model.str1());
  EXPECT_EQ(true, ::protos::GetExtension(&parsed_model, theme).ok());
}

TEST(CppGeneratedCode, ParseIntoPtrToModel) {
  TestModel model;
  model.set_str1("Test123");
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  EXPECT_EQ(true, ::protos::SetExtension(&model, theme, extension1).ok());
  ::upb::Arena arena;
  auto bytes = ::protos::Serialize(&model, arena);
  EXPECT_EQ(true, bytes.ok());
  ::protos::Ptr<TestModel> parsed_model =
      ::protos::CreateMessage<TestModel>(arena);
  EXPECT_TRUE(::protos::Parse(parsed_model, bytes.value()));
  EXPECT_EQ("Test123", parsed_model->str1());
  // Should return an extension even if we don't pass ExtensionRegistry
  // by promoting unknown.
  EXPECT_EQ(true, ::protos::GetExtension(parsed_model, theme).ok());
}

TEST(CppGeneratedCode, ParseWithExtensionRegistry) {
  TestModel model;
  model.set_str1("Test123");
  ThemeExtension extension1;
  extension1.set_ext_name("Hello World");
  EXPECT_EQ(true, ::protos::SetExtension(&model, theme, extension1).ok());
  EXPECT_EQ(true, ::protos::SetExtension(
                      &model, ThemeExtension::theme_extension, extension1)
                      .ok());
  ::upb::Arena arena;
  auto bytes = ::protos::Serialize(&model, arena);
  EXPECT_EQ(true, bytes.ok());
  ::protos::ExtensionRegistry extensions(
      {&theme, &other_ext, &ThemeExtension::theme_extension}, arena);
  TestModel parsed_model =
      ::protos::Parse<TestModel>(bytes.value(), extensions).value();
  EXPECT_EQ("Test123", parsed_model.str1());
  EXPECT_EQ(true, ::protos::GetExtension(&parsed_model, theme).ok());
  EXPECT_EQ(true, ::protos::GetExtension(&parsed_model,
                                         ThemeExtension::theme_extension)
                      .ok());
  EXPECT_EQ("Hello World", ::protos::GetExtension(
                               &parsed_model, ThemeExtension::theme_extension)
                               .value()
                               ->ext_name());
}

TEST(CppGeneratedCode, NameCollisions) {
  TestModel model;
  model.set_template_("test");
  EXPECT_EQ("test", model.template_());
  model.set_arena__("test");
  EXPECT_EQ("test", model.arena__());
}

TEST(CppGeneratedCode, SharedPointer) {
  std::shared_ptr<TestModel> model = std::make_shared<TestModel>();
  ::upb::Arena arena;
  auto bytes = protos::Serialize(model.get(), arena);
  EXPECT_TRUE(protos::Parse(model.get(), bytes.value()));
}

TEST(CppGeneratedCode, UniquePointer) {
  auto model = std::make_unique<TestModel>();
  ::upb::Arena arena;
  auto bytes = protos::Serialize(model.get(), arena);
  EXPECT_TRUE(protos::Parse(model.get(), bytes.value()));
}

TEST(CppGeneratedCode, Assignment) {
  TestModel model;
  model.set_category(5);
  model.mutable_child_model_1()->set_child_str1("text in child");
  TestModel model2 = model;
  EXPECT_EQ(5, model2.category());
  EXPECT_EQ(model2.child_model_1()->child_str1(), "text in child");
}

TEST(CppGeneratedCode, PtrAssignment) {
  TestModel model;
  model.mutable_child_model_1()->set_child_str1("text in child");
  ChildModel1 child_from_const_ptr = *model.child_model_1();
  EXPECT_EQ(child_from_const_ptr.child_str1(), "text in child");
  ChildModel1 child_from_ptr = *model.mutable_child_model_1();
  EXPECT_EQ(child_from_ptr.child_str1(), "text in child");
}

TEST(CppGeneratedCode, CopyConstructor) {
  TestModel model;
  model.set_category(6);
  TestModel model2(model);
  EXPECT_EQ(6, model2.category());
}

TEST(CppGeneratedCode, PtrConstructor) {
  TestModel model;
  model.mutable_child_model_1()->set_child_str1("text in child");
  ChildModel1 child_from_ptr(*model.mutable_child_model_1());
  EXPECT_EQ(child_from_ptr.child_str1(), "text in child");
  ChildModel1 child_from_const_ptr(*model.child_model_1());
  EXPECT_EQ(child_from_const_ptr.child_str1(), "text in child");
}

TEST(CppGeneratedCode, MutableToProxy) {
  TestModel model;
  ::protos::Ptr<ChildModel1> child = model.mutable_child_model_1();
  (void)child;
}

TEST(CppGeneratedCode, ProxyToCProxy) {
  TestModel model;
  ::protos::Ptr<ChildModel1> child = model.mutable_child_model_1();
  ::protos::Ptr<const ChildModel1> child2 = child;
  (void)child2;
}

bool ProxyToCProxyMethod(::protos::Ptr<const ChildModel1> child) {
  return child->child_str1() == "text in child";
}

TEST(CppGeneratedCode, PassProxyToCProxy) {
  TestModel model;
  model.mutable_child_model_1()->set_child_str1("text in child");
  EXPECT_TRUE(ProxyToCProxyMethod(model.mutable_child_model_1()));
}

TEST(CppGeneratedCode, PtrImplicitConversion) {
  TestModel model;
  model.set_int64(5);
  ::protos::Ptr<TestModel> model_ptr = &model;
  EXPECT_EQ(model_ptr->int64(), 5);
}

TEST(CppGeneratedCode, ClearSubMessage) {
  // Fill model.
  TestModel model;
  model.set_int64(5);
  auto new_child = model.mutable_child_model_1();
  new_child->set_child_str1("text in child");
  ThemeExtension extension1;
  extension1.set_ext_name("name in extension");
  EXPECT_TRUE(::protos::SetExtension(&model, theme, extension1).ok());
  EXPECT_TRUE(model.mutable_child_model_1()->has_child_str1());
  // Clear using Ptr<T>
  ::protos::ClearMessage(model.mutable_child_model_1());
  EXPECT_FALSE(model.mutable_child_model_1()->has_child_str1());
}

TEST(CppGeneratedCode, ClearMessage) {
  // Fill model.
  TestModel model;
  model.set_int64(5);
  model.set_str2("Hello");
  auto new_child = model.add_child_models();
  ASSERT_TRUE(new_child.ok());
  new_child.value()->set_child_str1("text in child");
  ThemeExtension extension1;
  extension1.set_ext_name("name in extension");
  EXPECT_TRUE(::protos::SetExtension(&model, theme, extension1).ok());
  // Clear using T*
  ::protos::ClearMessage(&model);
  // Verify that scalars, repeated fields and extensions are cleared.
  EXPECT_FALSE(model.has_int64());
  EXPECT_FALSE(model.has_str2());
  EXPECT_TRUE(model.child_models().empty());
  EXPECT_FALSE(::protos::HasExtension(&model, theme));
}

TEST(CppGeneratedCode, DeepCopy) {
  // Fill model.
  TestModel model;
  model.set_int64(5);
  model.set_str2("Hello");
  auto new_child = model.add_child_models();
  ASSERT_TRUE(new_child.ok());
  new_child.value()->set_child_str1("text in child");
  ThemeExtension extension1;
  extension1.set_ext_name("name in extension");
  EXPECT_TRUE(::protos::SetExtension(&model, theme, extension1).ok());
  TestModel target;
  target.set_b1(true);
  ::protos::DeepCopy(&model, &target);
  EXPECT_FALSE(target.b1()) << "Target was not cleared before copying content ";
  EXPECT_EQ(target.str2(), "Hello");
  EXPECT_TRUE(::protos::HasExtension(&target, theme));
}

TEST(CppGeneratedCode, HasExtensionAndRegistry) {
  // Fill model.
  TestModel source;
  source.set_int64(5);
  source.set_str2("Hello");
  auto new_child = source.add_child_models();
  ASSERT_TRUE(new_child.ok());
  new_child.value()->set_child_str1("text in child");
  ThemeExtension extension1;
  extension1.set_ext_name("name in extension");
  ASSERT_TRUE(::protos::SetExtension(&source, theme, extension1).ok());

  // Now that we have a source model with extension data, serialize.
  ::protos::Arena arena;
  std::string data = std::string(::protos::Serialize(&source, arena).value());

  // Test with ExtensionRegistry
  ::protos::ExtensionRegistry extensions({&theme}, arena);
  TestModel parsed_model = ::protos::Parse<TestModel>(data, extensions).value();
  EXPECT_TRUE(::protos::HasExtension(&parsed_model, theme));
}

// TODO(b/288491350) : Add BUILD rule to test failures below.
#ifdef TEST_CLEAR_MESSAGE_FAILURE
TEST(CppGeneratedCode, ClearConstMessageShouldFail) {
  // Fill model.
  TestModel model;
  model.set_int64(5);
  model.set_str2("Hello");
  // Only mutable_ can be cleared not Ptr<const T>.
  ::protos::ClearMessage(model.child_model_1());
}
#endif
