#include <gtest/gtest.h>
#include <gmock/gmock-matchers.h>
#include "Pgsql_Value.h"
#include "PrintTo_Qt.h"
#include <iterator>
#include <set>
#include <vector>

using namespace testing;
using namespace Pgsql;

TEST(Pgsql_Value, test_int4)
{
	Pgsql::Value v("1", int4_oid);
	int i = (int)v;
	ASSERT_EQ(i, 1);
}

TEST(Pgsql_Value, test_QDateTime)
{
	Pgsql::Value v("2017-10-22 12:34:56", timestamptz_oid);
	QDateTime dt = (QDateTime)v;
	ASSERT_EQ(dt, QDateTime(QDate(2017, 10, 22), QTime(12, 34, 56)));
}


TEST(Pgsql_Value, test_QDateTime_2)
{
	Pgsql::Value v("2017-12-01 09:38:17.339817+02", timestamptz_oid);
	QDateTime dt = (QDateTime)v;
	QDateTime exp(QDate(2017, 12, 1), QTime(9, 38, 17, 340),
					Qt::OffsetFromUTC, 2*3600);
	ASSERT_EQ(dt, exp);
}

TEST(Pgsql_Value, test_QDate)
{
	Pgsql::Value v("2017-10-22", date_oid);
	QDate d = v;
	ASSERT_EQ(d, QDate(2017, 10, 22));
}

TEST(Pgsql_Value, test_QTime)
{
	Pgsql::Value v("12:34:56", time_oid);
	QTime t = v;
	ASSERT_EQ(t, QTime(12, 34, 56));
}

TEST(Pgsql_Value, test_QTimeMS)
{
    Pgsql::Value v("09:38:17.339+02:00", timetz_oid);
	QTime t = v;
    ASSERT_EQ(t, QTime(9, 38, 17, 339));
}



TEST(Pgsql_Value, isString_int4)
{
	Pgsql::Value v("1", int4_oid);
	ASSERT_EQ(v.isString(), false);
}

TEST(Pgsql_Value, isString_varchar)
{
	Pgsql::Value v("1", varchar_oid);
	ASSERT_EQ(v.isString(), true);
}

TEST(Pgsql_Value, getAsVector_Ints)
{
	Pgsql::Value v("1 2", any_oid);
	std::vector<int> r;
	v.getAsVector<int>(std::back_inserter(r));

	ASSERT_EQ(r.size(), 2);
	ASSERT_EQ(r[0], 1);
	ASSERT_EQ(r[1], 2);
}



TEST(Pgsql_Value, getAsArray_Ints)
{
	Pgsql::Value v("{1,2}", text_array_oid);
	std::vector<int> r;
	v.getAsArray<int>(std::back_inserter(r));

	ASSERT_EQ(r.size(), 2);
	ASSERT_EQ(r[0], 1);
	ASSERT_EQ(r[1], 2);
}


TEST(Pgsql_Value, getAsArray_QDateTime)
{
	Pgsql::Value v("{\"2017-12-11 10:11:22\",\"2017-12-13 12:00:11\"}", text_array_oid);
	std::set<QDateTime> r;
	v.getAsArray<QDateTime>(std::inserter(r, r.end()));

	ASSERT_EQ(r.size(), 2);
}

TEST(Pgsql_Value, getAsArray_throws_on_NULL)
{
	Pgsql::Value v("{1,NULL,2}", text_array_oid);
	std::vector<int> r;
	try {
		v.getAsArray<int>(std::back_inserter(r));
		FAIL();
	} catch (std::runtime_error &) {
		SUCCEED();
	} catch (...) {
		FAIL();
	}
}

TEST(Pgsql_Value, getAsArray_default_on_NULL)
{
	Pgsql::Value v("{1,NULL,2}", text_array_oid);
	std::vector<int> r;
	try {
		v.getAsArray<int>(std::back_inserter(r), -1);
		ASSERT_EQ(r.size(), 3);
		ASSERT_EQ(r[0], 1);
		ASSERT_EQ(r[1], -1);
		ASSERT_EQ(r[2], 2);
	} catch (...) {
		FAIL();
	}
}

TEST(Pgsql_Value, getAsArray_ignore_NULL)
{
	Pgsql::Value v("{1,NULL,2}", text_array_oid);
	std::vector<int> r;
	try {
		v.getAsArray<int>(std::back_inserter(r), NullHandling::Ignore);
		ASSERT_EQ(r.size(), 2);
		ASSERT_EQ(r[0], 1);
		ASSERT_EQ(r[1], 2);
	} catch (...) {
		FAIL();
	}
}

TEST(Pgsql_Value, getAsArrayOptional)
{
	Pgsql::Value v("{1,NULL,2}", text_array_oid);
	std::vector<std::optional<int>> r;
	try {
		v.getAsArrayOfOptional<int>(std::back_inserter(r));
		ASSERT_EQ(r.size(), 3);
		ASSERT_EQ(r[0], 1);
		ASSERT_EQ(r[1], std::nullopt);
		ASSERT_EQ(r[2], 2);
	} catch (...) {
		FAIL();
	}
}

