//======================================================================
//-----------------------------------------------------------------------
/**
 * @file		prod_tests1.cpp
 * @brief		product code access test
 *
 * @author		t.shirayanagi
 * @par			copyright
 * Copyright (C) 2012-2015, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================

//======================================================================
// include
#include "prod_tests.hpp"

namespace prod_test
{

int ProdClass::m_y = 0;

}

namespace prod_test
{

static ProdClass s_prod;

// IUTEST_FRIEND_TEST を使ってのアクセス
IUTEST(ProdTest, Friend)
{
	s_prod.SetX(1);
	IUTEST_EXPECT_EQ(1, s_prod.GetX());

	s_prod.m_x = 2;
	IUTEST_EXPECT_EQ(2, s_prod.GetX());
}

class ProdFixtureTest : public ::iutest::Test {};

IUTEST_F(ProdFixtureTest, Friend)
{
	s_prod.SetX(1);
	IUTEST_EXPECT_EQ(1, s_prod.GetX());

	s_prod.m_x = 2;
	IUTEST_EXPECT_EQ(2, s_prod.GetX());
}

#if IUTEST_HAS_PARAM_TEST

class ProdParamTest : public ::iutest::TestWithParam<int> {};

IUTEST_INSTANTIATE_TEST_CASE_P(X, ProdParamTest, ::iutest::Values(0));

IUTEST_P(ProdParamTest, Friend)
{
	s_prod.SetX(1);
	IUTEST_EXPECT_EQ(1, s_prod.GetX());

	s_prod.m_x = 2;
	IUTEST_EXPECT_EQ(2, s_prod.GetX());
}

#endif

#if IUTEST_HAS_TYPED_TEST

template<typename T>
class ProdTypedTest : public ::iutest::Test {};

IUTEST_TYPED_TEST_CASE(ProdTypedTest, int);

IUTEST_TYPED_TEST(ProdTypedTest, Friend)
{
	s_prod.SetX(1);
	IUTEST_ASSERT_EQ(1, s_prod.GetX());

	s_prod.m_x = 2;
	IUTEST_ASSERT_EQ(2, s_prod.GetX());
}

#endif

#if IUTEST_HAS_TYPED_TEST_P

typedef ::iutest::Types<int, float> ProdTypeParams;

template<typename T>
class ProdTypeParamTest : public ::iutest::Test {};

IUTEST_TYPED_TEST_CASE_P(ProdTypeParamTest);

IUTEST_TYPED_TEST_P(ProdTypeParamTest, Friend)
{
	s_prod.SetX(1);
	IUTEST_ASSERT_EQ(1, s_prod.GetX());

	s_prod.m_x = 2;
	IUTEST_ASSERT_EQ(2, s_prod.GetX());
}

IUTEST_REGISTER_TYPED_TEST_CASE_P(ProdTypeParamTest, Friend);


#endif


#if IUTEST_HAS_PEEP

static ProdClass2 s_prod2;

// peep を使ってのアクセス
IUTEST_MAKE_PEEP(int ProdClass::*, ProdClass, m_x);
IUTEST_MAKE_PEEP(const int ProdClass::*, ProdClass, m_c);

IUTEST_MAKE_PEEP(int ProdClass2::*, ProdClass2, m_x);

IUTEST(PeepTest, PeepMacro)
{
	IUTEST_PEEP_GET(s_prod, ProdClass, m_x) = 4;
	IUTEST_EXPECT_EQ(4, s_prod.GetX());

	IUTEST_EXPECT_EQ(4, IUTEST_PEEP_GET(s_prod, ProdClass, m_x));

	IUTEST_PEEP_GET(s_prod2, ProdClass2, m_x) = 42;
	IUTEST_EXPECT_EQ(42, s_prod2.GetX());
	
	IUTEST_EXPECT_EQ(42, IUTEST_PEEP_GET(s_prod2, ProdClass2, m_x));
}

#if IUTEST_HAS_PEEP_CLASS

IUTEST(PeepClassTest, PeepObject)
{
	IUTEST_PEEP(ProdClass, m_x) prod_class_x(&s_prod);
	prod_class_x = 5;
	IUTEST_EXPECT_EQ(5, s_prod.GetX());
	prod_class_x += prod_class_x;
	IUTEST_EXPECT_EQ(10, s_prod.GetX());

	IUTEST_EXPECT_EQ(10, prod_class_x);

	IUTEST_PEEP(ProdClass2, m_x) prod_class2_x(&s_prod2);
	prod_class2_x = 54;
	IUTEST_EXPECT_EQ(54, s_prod2.GetX());
	prod_class2_x += prod_class2_x;
	IUTEST_EXPECT_EQ(108, s_prod2.GetX());

	IUTEST_EXPECT_EQ(108, prod_class2_x);
}

#endif

IUTEST(PeepTest, A1)
{
	IUTEST_PEEP_GET(s_prod, ProdClass, m_a) = 1;
	IUTEST_EXPECT_EQ(1, s_prod.GetA());

	IUTEST_EXPECT_EQ(1, IUTEST_PEEP_GET(s_prod, ProdClass, m_a));
}

IUTEST(PeepTest, Const)
{
	// マクロ版
	IUTEST_EXPECT_EQ(42, IUTEST_PEEP_GET(s_prod, ProdClass, m_c));
}
	
#if IUTEST_HAS_PEEP_CLASS
IUTEST(PeepClassTest, Const)
{
	// object 版
	IUTEST_PEEP(ProdClass, m_c) prod_class_c(&s_prod);
	IUTEST_EXPECT_EQ(42, prod_class_c);
}
#endif

IUTEST_MAKE_PEEP(int *, ProdClass, m_y);

IUTEST(PeepTest, StaticPeep)
{
	IUTEST_PEEP_STATIC_GET(ProdClass, m_y) = 4;
	IUTEST_EXPECT_EQ(4, ProdClass::GetY());

	IUTEST_EXPECT_EQ(4, IUTEST_PEEP_STATIC_GET(ProdClass, m_y));
}
	
#if IUTEST_HAS_PEEP_CLASS
IUTEST(PeepClassTest, StaticPeep)
{
	// object 版
	IUTEST_PEEP(ProdClass, m_y) prod_class_y;
	prod_class_y = 5;
	IUTEST_EXPECT_EQ(5, ProdClass::GetY());
	prod_class_y *= 2;
	IUTEST_EXPECT_EQ(10, ProdClass::GetY());

	IUTEST_PEEP(ProdClass, m_y)(1);
	IUTEST_EXPECT_EQ(1, prod_class_y);

	IUTEST_PEEP(ProdClass, m_y) prod_class_y2 = 2;
	IUTEST_EXPECT_EQ(2, prod_class_y2);
}
#endif

#if IUTEST_HAS_PEEP_FUNC

IUTEST_MAKE_PEEP(void (ProdClass::*)(int), ProdClass, SetX);
IUTEST_MAKE_PEEP(int (ProdClass::*)() const, ProdClass, ConstGetX);

IUTEST(PeepTest, Function)
{
	IUTEST_PEEP_GET(s_prod, ProdClass, SetX)(100);
	IUTEST_EXPECT_EQ(100, s_prod.GetX());
	IUTEST_EXPECT_EQ(100, IUTEST_PEEP_GET(s_prod, ProdClass, ConstGetX)());
}
	
#if IUTEST_HAS_PEEP_CLASS
IUTEST(PeepClassTest, Function)
{
	IUTEST_PEEP(ProdClass, SetX) peep_set(&s_prod);
	peep_set(101);
	IUTEST_EXPECT_EQ(101, s_prod.GetX());

	IUTEST_PEEP(ProdClass, ConstGetX) peep_get(&s_prod);
	IUTEST_EXPECT_EQ(101, peep_get());
}
#endif

#endif

#if IUTEST_HAS_PEEP_STATIC_FUNC

IUTEST_MAKE_PEEP(void (*)(int), ProdClass, SetY);

IUTEST(PeepTest, StaticFunction)
{
	IUTEST_PEEP_STATIC_GET(ProdClass, SetY)(100);
	IUTEST_EXPECT_EQ(100, ProdClass::GetY());
}
	
	// object 版
#if IUTEST_HAS_PEEP_CLASS
IUTEST(PeepClassTest, StaticFunction)
{
	IUTEST_PEEP(ProdClass, SetY) peep;
	peep(101);
	IUTEST_EXPECT_EQ(101, ProdClass::GetY());
}
#endif

#endif

#endif

}


#if IUTEST_HAS_PEEP

// peep を使ってのアクセス
IUTEST_MAKE_PEEP(int prod_test::ProdClass::*, prod_test::ProdClass, m_z);
IUTEST_MAKE_PEEP(int prod_test::ProdClass::*, prod_test::ProdClass, m_x);

IUTEST(PeepTest, ScopedPeep)
{
	// マクロ版
	{
		IUTEST_PEEP_GET(prod_test::s_prod, prod_test::ProdClass, m_z) = 4;
		IUTEST_EXPECT_EQ(4, prod_test::s_prod.GetZ());

		IUTEST_EXPECT_EQ(4, IUTEST_PEEP_GET(prod_test::s_prod, prod_test::ProdClass, m_z));
	}
	{
		IUTEST_PEEP_GET(prod_test::s_prod, prod_test::ProdClass, m_x) = 4;
		IUTEST_EXPECT_EQ(4, prod_test::s_prod.GetX());

		IUTEST_EXPECT_EQ(4, IUTEST_PEEP_GET(prod_test::s_prod, prod_test::ProdClass, m_x));
	}
}

#if IUTEST_HAS_PEEP_CLASS

IUTEST(PeepClassTest, ScopedPeep)
{
	{
		IUTEST_PEEP(prod_test::ProdClass, m_z) prod_class_z(&prod_test::s_prod);
		prod_class_z = 5;
		IUTEST_EXPECT_EQ(5, prod_test::s_prod.GetZ());

		IUTEST_EXPECT_EQ(5, prod_class_z);
	}
	{
		IUTEST_PEEP(prod_test::ProdClass, m_z) prod_class_z(&prod_test::s_prod);
		prod_class_z = 5;
		IUTEST_EXPECT_EQ(5, prod_test::s_prod.GetZ());

		IUTEST_EXPECT_EQ(5, prod_class_z);
	}
}
#endif

#endif
