#include "cpp_vector_type_test.h"

#include "cpp_vector_type_generated.h"
#include "test_assert.h"

namespace flatbuffers {
namespace tests {

// Exercises the --cpp-vector-type flatc option (see
// tests/cpp_vector_type.fbs and tests/test_vector_type.h), which replaces
// std::vector with a custom vector-like container in the generated Object
// API. This covers every CreateVector*-family code path in Pack(): plain
// scalars, bool, enum-cast, vector-of-string, vector-of-struct and
// vector-of-table, then round-trips everything back through UnPackTo().
void CppVectorTypeTest() {
  using CppVectorTypeNS::CppVectorTypeColor_Blue;
  using CppVectorTypeNS::CppVectorTypeColor_Green;
  using CppVectorTypeNS::CppVectorTypeColor_Red;
  using CppVectorTypeNS::CppVectorTypeMonsterT;
  using CppVectorTypeNS::CppVectorTypeTest;
  using CppVectorTypeNS::CppVectorTypeTestT;
  using CppVectorTypeNS::CppVectorTypeVec2;

  // ---------------------------------------
  // 1) Build a native object using the custom vector container for every
  //    vector field (scalars, bools, enums, strings, structs and tables).
  // ---------------------------------------
  CppVectorTypeTestT src;
  src.ints.push_back(1);
  src.ints.push_back(2);
  src.ints.push_back(3);

  src.flags.push_back(true);
  src.flags.push_back(false);
  src.flags.push_back(true);

  src.colors.push_back(CppVectorTypeColor_Red);
  src.colors.push_back(CppVectorTypeColor_Green);
  src.colors.push_back(CppVectorTypeColor_Blue);

  src.strings.push_back("hello");
  src.strings.push_back("world");

  src.positions.push_back(CppVectorTypeVec2(1.0f, 2.0f));
  src.positions.push_back(CppVectorTypeVec2(3.0f, 4.0f));

  src.monsters.emplace_back(new CppVectorTypeMonsterT());
  src.monsters[0]->id = 111;
  src.monsters.emplace_back(new CppVectorTypeMonsterT());
  src.monsters[1]->id = 222;

  // ---------------------------------------
  // 2) Exercise the copy constructor / copy assignment operator generated
  //    for object-API types (--gen-compare requires these too), which rely
  //    on the custom vector's own copy ctor plus reserve()/emplace_back()
  //    for the vector-of-pointer (table) field.
  // ---------------------------------------
  CppVectorTypeTestT copy_of_src(src);
  TEST_EQ(copy_of_src == src, true);
  TEST_ASSERT(copy_of_src.monsters[0].get() != src.monsters[0].get());
  TEST_EQ(copy_of_src.monsters[0]->id, 111);

  // ---------------------------------------
  // 3) Pack into a FlatBuffer and verify the wire-format contents.
  // ---------------------------------------
  flatbuffers::FlatBufferBuilder fbb;
  fbb.Finish(CppVectorTypeTest::Pack(fbb, &src));

  const auto* fb =
      flatbuffers::GetRoot<CppVectorTypeTest>(fbb.GetBufferPointer());

  TEST_EQ(fb->ints()->size(), 3u);
  TEST_EQ(fb->ints()->Get(0), 1);
  TEST_EQ(fb->ints()->Get(1), 2);
  TEST_EQ(fb->ints()->Get(2), 3);

  TEST_EQ(fb->flags()->size(), 3u);
  TEST_EQ(fb->flags()->Get(0) != 0, true);
  TEST_EQ(fb->flags()->Get(1) != 0, false);
  TEST_EQ(fb->flags()->Get(2) != 0, true);

  TEST_EQ(fb->colors()->size(), 3u);
  TEST_EQ(fb->colors()->Get(0), CppVectorTypeColor_Red);
  TEST_EQ(fb->colors()->Get(1), CppVectorTypeColor_Green);
  TEST_EQ(fb->colors()->Get(2), CppVectorTypeColor_Blue);

  TEST_EQ(fb->strings()->size(), 2u);
  TEST_EQ_STR(fb->strings()->Get(0)->c_str(), "hello");
  TEST_EQ_STR(fb->strings()->Get(1)->c_str(), "world");

  TEST_EQ(fb->positions()->size(), 2u);
  TEST_EQ(fb->positions()->Get(0)->x(), 1.0f);
  TEST_EQ(fb->positions()->Get(0)->y(), 2.0f);
  TEST_EQ(fb->positions()->Get(1)->x(), 3.0f);
  TEST_EQ(fb->positions()->Get(1)->y(), 4.0f);

  TEST_EQ(fb->monsters()->size(), 2u);
  TEST_EQ(fb->monsters()->Get(0)->id(), 111);
  TEST_EQ(fb->monsters()->Get(1)->id(), 222);

  // ---------------------------------------
  // 4) Unpack back into a fresh native object and verify a full round-trip
  //    through the custom vector container.
  // ---------------------------------------
  CppVectorTypeTestT dst;
  fb->UnPackTo(&dst);

  TEST_EQ(dst == src, true);

  TEST_EQ(dst.ints.size(), 3u);
  TEST_EQ(dst.ints[0], 1);
  TEST_EQ(dst.ints[1], 2);
  TEST_EQ(dst.ints[2], 3);

  TEST_EQ(dst.flags.size(), 3u);
  TEST_EQ(dst.flags[0], true);
  TEST_EQ(dst.flags[1], false);
  TEST_EQ(dst.flags[2], true);

  TEST_EQ(dst.colors.size(), 3u);
  TEST_EQ(dst.colors[0], CppVectorTypeColor_Red);
  TEST_EQ(dst.colors[1], CppVectorTypeColor_Green);
  TEST_EQ(dst.colors[2], CppVectorTypeColor_Blue);

  TEST_EQ(dst.strings.size(), 2u);
  TEST_EQ_STR(dst.strings[0].c_str(), "hello");
  TEST_EQ_STR(dst.strings[1].c_str(), "world");

  TEST_EQ(dst.positions.size(), 2u);
  TEST_EQ(dst.positions[0].x(), 1.0f);
  TEST_EQ(dst.positions[0].y(), 2.0f);
  TEST_EQ(dst.positions[1].x(), 3.0f);
  TEST_EQ(dst.positions[1].y(), 4.0f);

  TEST_EQ(dst.monsters.size(), 2u);
  TEST_ASSERT(dst.monsters[0] != nullptr);
  TEST_ASSERT(dst.monsters[1] != nullptr);
  TEST_EQ(dst.monsters[0]->id, 111);
  TEST_EQ(dst.monsters[1]->id, 222);
}

}  // namespace tests
}  // namespace flatbuffers
