/*
 * 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.
 */

#include "../logunit.h"
#include "util/compare.h"
#include <log4cxx/helpers/threadutility.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/patternlayout.h>
#include <log4cxx/fileappender.h>
#include <log4cxx/logmanager.h>

using namespace log4cxx;
using namespace log4cxx::helpers;


LOGUNIT_CLASS(ThreadUtilityTest)
{
	LOGUNIT_TEST_SUITE(ThreadUtilityTest);
	LOGUNIT_TEST(testNullFunctions);
	LOGUNIT_TEST(testCustomFunctions);
	LOGUNIT_TEST(testDefaultFunctions);
#if LOG4CXX_HAS_PTHREAD_SETNAME || defined(_WIN32)
	LOGUNIT_TEST(testThreadNameLogging);
#endif
	LOGUNIT_TEST_SUITE_END();
#ifdef _DEBUG
	struct Fixture
	{
		Fixture() {
			LogLog::setInternalDebugging(true);
		}
	} suiteFixture;
#endif

public:
	void testNullFunctions()
	{
		auto thrUtil = ThreadUtility::instance();

		thrUtil->configureFuncs( nullptr, nullptr, nullptr );

		std::thread t = thrUtil->createThread( LOG4CXX_STR("FooName"), []() {} );

		t.join();
	}

	void testCustomFunctions()
	{
		auto thrUtil = ThreadUtility::instance();
		int num_pre = 0;
		int num_started = 0;
		int num_run = 0;
		int num_post = 0;

		thrUtil->configureFuncs(
			[&num_pre]()
		{
			num_pre++;
		},
		[&num_started]( LogString,
			std::thread::id,
			std::thread::native_handle_type )
		{
			num_started++;
		},
		[&num_post]()
		{
			num_post++;
		}
		);

		std::thread t = thrUtil->createThread( LOG4CXX_STR("FooName"), [&num_run]()
		{
			num_run++;
		} );

		t.join();

		LOGUNIT_ASSERT_EQUAL( num_pre, 1 );
		LOGUNIT_ASSERT_EQUAL( num_started, 1 );
		LOGUNIT_ASSERT_EQUAL( num_run, 1 );
		LOGUNIT_ASSERT_EQUAL( num_post, 1 );
	}

	void testDefaultFunctions()
	{
		ThreadUtility::configure( ThreadConfigurationType::BlockSignalsAndNameThread );

		auto thrUtil = ThreadUtility::instance();

		std::thread t = thrUtil->createThread( LOG4CXX_STR("FooName"), []() {} );

		t.join();
	}

	void testThreadNameLogging()
	{
		auto layout = std::make_shared<PatternLayout>(LOG4CXX_STR("%T %m%n"));
		LogString logFileName(LOG4CXX_STR("output/threadnametestcase.log"));
		AppenderPtr appender(new FileAppender(layout, logFileName, false));
		auto logger = LogManager::getRootLogger();
		logger->addAppender(appender);
		std::thread t = ThreadUtility::instance()->createThread( LOG4CXX_STR("FooName"), [logger]() {
			LOG4CXX_DEBUG(logger, "Test message");
		});
		t.join();
		LOGUNIT_ASSERT(Compare::compare(logFileName, LOG4CXX_FILE("witness/threadnametestcase.1")));
	}
};


LOGUNIT_TEST_SUITE_REGISTRATION(ThreadUtilityTest);

