//
// Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <boost/mysql/field_view.hpp>

#include <boost/mysql/impl/internal/protocol/binary_serialization.hpp>

#include <boost/test/unit_test.hpp>

#include "serialization_test.hpp"
#include "test_common/create_basic.hpp"

using namespace boost::mysql;
using namespace boost::mysql::test;

BOOST_AUTO_TEST_SUITE(test_binary_serialization)

BOOST_AUTO_TEST_CASE(serialize_field_view)
{
    std::uint8_t blob_buffer[] = {0x70, 0x00, 0x01};
    struct
    {
        const char* name;
        field_view value;
        std::vector<std::uint8_t> serialized;
    } test_cases[]{
  // Strings and ints: extensive testing already done. Ensure
  // we call the right function
        {"string", field_view("abc"), {0x03, 0x61, 0x62, 0x63}},
        {"blob", field_view(blob_view(blob_buffer)), {0x03, 0x70, 0x00, 0x01}},
        {"uint64",
         field_view(std::uint64_t(0xf8f9fafbfcfdfeff)),
         {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}},
        {"int64",
         field_view(std::int64_t(-0x0706050403020101)),
         {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}},

        {"float_fractional_negative", field_view(-4.2f), {0x66, 0x66, 0x86, 0xc0}},
        {"float_fractional_positive", field_view(4.2f), {0x66, 0x66, 0x86, 0x40}},
        {"float_positive_exp_positive_fractional", field_view(3.14e20f), {0x01, 0x2d, 0x88, 0x61}},
        {"float_zero", field_view(0.0f), {0x00, 0x00, 0x00, 0x00}},

        {"double_fractional_negative", field_view(-4.2), {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0xc0}},
        {"double_fractional_positive", field_view(4.2), {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40}},
        {"double_positive_exp_positive_fractional",
         field_view(3.14e200),
         {0xce, 0x46, 0x3c, 0x76, 0x9c, 0x68, 0x90, 0x69}},
        {"double_zero", field_view(0.0), {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},

        {"date_regular", field_view(date(2010u, 3u, 28u)), {0x04, 0xda, 0x07, 0x03, 0x1c}},
        {"date_min", field_view(date(1000u, 1u, 1u)), {0x04, 0xe8, 0x03, 0x01, 0x01}},
        {"date_mysqlmax", field_view(date(9999u, 12u, 31u)), {0x04, 0x0f, 0x27, 0x0c, 0x1f}},
        {"date_max", field_view(date(0xffff, 0xff, 0xff)), {0x04, 0xff, 0xff, 0xff, 0xff}},
        {"date_zero", field_view(date()), {0x04, 0x00, 0x00, 0x00, 0x00}},

        {"datetime_regular",
         field_view(datetime(2010u, 1u, 1u, 23u, 1u, 59u, 967510u)),
         {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}},
        {"datetime_min",
         field_view(datetime(0, 1, 1)),
         {0x0b, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
        {"datetime_mysqlmax",
         field_view(datetime(9999, 12, 31, 23, 59, 59, 999999)),
         {0x0b, 0x0f, 0x27, 0x0c, 0x1f, 0x17, 0x3b, 0x3b, 0x3f, 0x42, 0x0f, 0x00}},
        {"datetime_max",
         field_view(datetime(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff)),
         {0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
        {"datetime_zero",
         field_view(datetime()),
         {0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},

        {"time_positive_u",
         field_view(maket(0, 0, 0, 321000)),
         {0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00}},
        {"time_positive_hmsu",
         field_view(maket(838, 59, 58, 999000)),
         {0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00}},
        {"time_negative_u",
         field_view(-maket(0, 0, 0, 321000)),
         {0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00}},
        {"time_negative_hmsu",
         field_view(-maket(838, 59, 58, 999000)),
         {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00}},

 // NULL is transmitted as the NULL bitmap, so nothing is expected as output
        {"null", field_view(), {}},
    };

    for (const auto& tc : test_cases)
    {
        BOOST_TEST_CONTEXT(tc.name) { do_serialize_test(tc.value, tc.serialized); }
    }
}

BOOST_AUTO_TEST_SUITE_END()