/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#if !defined(_LOG4CXX_LOGUNIT_H)
#define _LOG4CXX_LOGUNIT_H


#if defined(_MSC_VER)
	#pragma warning (push)
	#pragma warning ( disable: 4231 4251 4275 4786 )
#endif

#include "abts.h"
#include <exception>
#include <map>
#include <sstream>
#include <string>
#include <vector>

#include <log4cxx/logstring.h>

namespace LogUnit
{
class TestException : public std::exception
{
	public:
		TestException();
		TestException(const TestException&);
		TestException& operator=(const TestException&);
};
class AssertException : public std::exception
{
	public:
		AssertException(std::string msg, int lineno);
		AssertException(bool expected, const char* actualExpr, int lineno);
		AssertException(const AssertException&);
		AssertException& operator=(const AssertException&);
		virtual ~AssertException() throw();
		std::string getMessage() const;
		int getLine() const;
	private:
		std::string msg;
		int lineno;
};
class TestFixture
{
	public:
		TestFixture();
		virtual ~TestFixture();
		void setCase(abts_case* tc);
		virtual void setUp();
		virtual void tearDown();

		void assertEquals(const int expected, const int actual, int lineno);
		void assertEquals(const std::string expected,
			const std::string actual,
			const char* expectedExpr,
			const char* actualExpr,
			int lineno);
		void assertEquals(const char* expected,
			const char* actual,
			const char* expectedExpr,
			const char* actualExpr,
			int lineno);
#if LOG4CXX_LOGCHAR_IS_WCHAR || LOG4CXX_WCHAR_T_API
		void assertEquals(const std::wstring expected,
			const std::wstring actual,
			const char* expectedExpr,
			const char* actualExpr,
			int lineno);
#endif
#if LOG4CXX_LOGCHAR_IS_UNICHAR || LOG4CXX_UNICHAR_API || LOG4CXX_CFSTRING_API
		void assertEquals(const std::basic_string<log4cxx::UniChar> expected,
			const std::basic_string<log4cxx::UniChar> actual,
			const char* expectedExpr,
			const char* actualExpr, int lineno);
#endif
		template<class T>
		void assertEquals(const T& expected,
			const T& actual,
			const char* expectedExpr,
			const char* actualExpr,
			int lineno)
		{
			if (expected != actual)
			{
				std::string msg(expectedExpr);
				msg.append(" != ");
				msg.append(actualExpr);
				abts_fail(tc, msg.c_str(), lineno);
			}
		}
	private:
		TestFixture(const TestFixture&);
		TestFixture& operator=(const TestFixture&);
		abts_case* tc;
};
template<class T>
void runTest(abts_case* tc, void (T::*func)())
{
	T ti;
	ti.setCase(tc);
	ti.setUp();

	try
	{
		(ti.*func)();
	}
	catch (TestException&)
	{
	}
	catch (AssertException& fx)
	{
		abts_fail(tc, fx.getMessage().c_str(), fx.getLine());
	}
	catch (std::exception& e)
	{
		const char* what = e.what();
		std::ostringstream oss;
		oss << "Unexpected std::exception: "
			<< (what ? what : "what() == NULL");
		abts_fail(tc, oss.str().c_str(), -1);
	}
	catch (...)
	{
		abts_fail(tc, "Unexpected exception", -1);
	}

	ti.tearDown();
}
template<class T, class X>
void runTestWithException(abts_case* tc, void (T::*func)())
{
	T ti;
	ti.setCase(tc);
	ti.setUp();

	try
	{
		(ti.*func)();
	}
	catch (TestException&)
	{
	}
	catch (AssertException& fx)
	{
		abts_fail(tc, fx.getMessage().c_str(), fx.getLine());
	}
	catch (X&)
	{
	}
	catch (...)
	{
		abts_fail(tc, "Unexpected exception", -1);
	}

	ti.tearDown();
}
class TestSuite
{
	public:
		TestSuite(const char* filename);
		void addTest(const char* testName, test_func func);
		abts_suite* run(abts_suite* suite) const;
		std::string getName() const;
		void setDisabled(bool newVal);
		bool isDisabled() const;
	private:
		TestSuite(const TestSuite&);
		TestSuite& operator=(const TestSuite&);
		typedef std::vector<test_func> TestList;
		TestList test_funcs;
		std::string filename;
		bool disabled;
};
typedef std::vector< std::pair<std::string, const TestSuite*> > SuiteList;
SuiteList& getAllSuites();
template<class T>
class RegisterSuite
{
	public:
		RegisterSuite()
		{
			T::populateSuite();
			TestSuite* suite = T::getSuite();
			LogUnit::getAllSuites().push_back(SuiteList::value_type(suite->getName(), suite));
		}
};
template<class T>
class RegisterDisabledSuite
{
	public:
		RegisterDisabledSuite()
		{
			T::populateSuite();
			TestSuite* suite = T::getSuite();
			suite->setDisabled(true);
			LogUnit::getAllSuites().push_back(SuiteList::value_type(suite->getName(), suite));
		}
};
}

#define LOGUNIT_CLASS(x) class x : public LogUnit::TestFixture


#define LOGUNIT_TEST_SUITE(TF)                        \
	public:                                               \
	static LogUnit::TestSuite* getSuite() {          \
		static LogUnit::TestSuite suite(__FILE__);    \
		return &suite;                                \
	}                                                \
	private:                                         \
	class RegisterSuite {                            \
		public:                                          \
			typedef TF ThisFixture

#define LOGUNIT_TEST(testName)          \
	class testName ## Registration {   \
		public:                            \
			testName ## Registration() {    \
				ThisFixture::getSuite()->addTest(#testName, &testName ## Registration :: run); \
			}                               \
			static void run(abts_case* tc, void*) { \
				LogUnit::runTest<ThisFixture>(tc, &ThisFixture::testName); \
			}                                       \
	} register ## testName

#define LOGUNIT_TEST_EXCEPTION(testName, Exception)  \
	class testName ## Registration {   \
		public:                            \
			testName ## Registration() {    \
				ThisFixture::getSuite()->addTest(#testName, &testName ## Registration :: run); \
			}                               \
			static void run(abts_case* tc, void*) { \
				LogUnit::runTestWithException<ThisFixture, Exception>(tc, &ThisFixture::testName); \
			}                                       \
	} register ## testName


#define LOGUNIT_TEST_SUITE_END() \
	};                             \
	public:                        \
	static void populateSuite() {         \
		static RegisterSuite registration; \
	}                                      \
	private:                               \
	void nop()


#define LOGUNIT_TEST_SUITE_REGISTRATION(TF) \
	static LogUnit::RegisterSuite<TF> registration;

#define LOGUNIT_TEST_SUITE_REGISTRATION_DISABLED(TF) \
	static LogUnit::RegisterDisabledSuite<TF> registration;


#define LOGUNIT_ASSERT(     x)                                  { if (!(x)) throw LogUnit::AssertException(true, #x, __LINE__); }
#define LOGUNIT_ASSERT_SRCL(x, srcLine)                         { if (!(x)) throw LogUnit::AssertException(true, #x, srcLine);  }
#define LOGUNIT_ASSERT_EQUAL(       expected, actual)           assertEquals(expected, actual, #expected, #actual, __LINE__)
#define LOGUNIT_ASSERT_EQUAL_SRCL(  expected, actual, srcLine)  assertEquals(expected, actual, #expected, #actual, srcLine)
#define LOGUNIT_FAIL(msg)                                       throw LogUnit::AssertException(msg, __LINE__)


#if defined(_MSC_VER)
	#pragma warning (pop)
#endif

#endif

