
/*
 * 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 <log4cxx/ndc.h>
#include <log4cxx/file.h>
#include <log4cxx/logger.h>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/patternlayout.h>
#include "insertwide.h"
#include "logunit.h"
#include "util/compare.h"

static log4cxx::NDC ndc("ndctest");

using namespace log4cxx;

LOGUNIT_CLASS(NDCTestCase)
{
	static File TEMP;
	static LoggerPtr logger;

	LOGUNIT_TEST_SUITE(NDCTestCase);
	LOGUNIT_TEST(testPushPop);
	LOGUNIT_TEST(test1);
	LOGUNIT_TEST(testInherit);
	LOGUNIT_TEST(testFieldPrecision);
	LOGUNIT_TEST_SUITE_END();

public:

	void setUp()
	{
	}

	void tearDown()
	{
		auto rep = logger->getLoggerRepository();

		if (rep)
		{
			rep->resetConfiguration();
		}
	}

	/**
	 *   Push and pop a value from the NDC
	 */
	void testPushPop()
	{
		NDC::push("trivial context");
		LogString actual(NDC::pop());
		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("trivial context"), actual);
	}


	void test1()
	{
		auto status = PropertyConfigurator::configure(File("input/ndc/NDC1.properties"));
		LOGUNIT_ASSERT_EQUAL(status, spi::ConfigurationStatus::Configured);
		common();
		LOGUNIT_ASSERT(Compare::compare(TEMP, File("witness/ndc/NDC.1")));
	}

	static void common()
	{
		commonLog();
		NDC::push("n1");
		commonLog();
		NDC::push("n2");
		NDC::push("n3");
		commonLog();
		NDC::pop();
		commonLog();
		NDC::clear();
		commonLog();
	}

	static void commonLog()
	{
		LOG4CXX_DEBUG(logger, "m1");
		LOG4CXX_INFO(logger, "m2");
		LOG4CXX_WARN(logger, "m3");
		LOG4CXX_ERROR(logger, "m4");
		LOG4CXX_FATAL(logger, "m5");
	}

	void testInherit()
	{
		NDC::push("hello");
		NDC::push("world");
		NDC::Stack* clone = NDC::cloneStack();
		NDC::clear();
		NDC::push("discard");
		NDC::inherit(clone);
		LogString expected1(LOG4CXX_STR("world"));
		LOGUNIT_ASSERT_EQUAL(expected1, NDC::pop());
		LogString expected2(LOG4CXX_STR("hello"));
		LOGUNIT_ASSERT_EQUAL(expected2, NDC::pop());
		LogString expected3;
		LOGUNIT_ASSERT_EQUAL(expected3, NDC::pop());
	}

	/// Check NDC formatting uses to suffix when the maximum field length is exceeded.
	void testFieldPrecision()
	{
		NDC item1("context1");
		NDC item2("context2");
		NDC item3("context3");
		LogString output;
		PatternLayout l{ LOG4CXX_STR("%-5p %c - %.20x %m") };
		l.format(output, std::make_shared<spi::LoggingEvent>(LOG4CXX_STR("NDC.LayoutTest"), Level::getInfo(), LOG4CXX_STR("Message"), spi::LocationInfo::getLocationUnavailable()));
		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("INFO  NDC.LayoutTest - t1 context2 context3 Message"), output);
	}

};


File NDCTestCase::TEMP("output/ndc");
LoggerPtr NDCTestCase::logger(Logger::getLogger("org.apache.log4j.NDCTestCase"));

LOGUNIT_TEST_SUITE_REGISTRATION(NDCTestCase);
