/*
 * 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/logger.h>
#include "logunit.h"
//
//  If there is no support for wchar_t logging then
//     there is not a consistent way to get the test characters logged
//
#if LOG4CXX_WCHAR_T_API


#include <log4cxx/patternlayout.h>
#include <log4cxx/fileappender.h>
#include <log4cxx/level.h>

#include "util/binarycompare.h"
#include <log4cxx/file.h>
#include <log4cxx/helpers/pool.h>

using namespace log4cxx;
using namespace log4cxx::util;
using namespace log4cxx::helpers;

/**
 * Tests support for encoding specification.
 *
 *
 */
LOGUNIT_CLASS(EncodingTest)
{
	LOGUNIT_TEST_SUITE(EncodingTest);
	LOGUNIT_TEST(testASCII);
	LOGUNIT_TEST(testLatin1);
	LOGUNIT_TEST(testUtf8);
	LOGUNIT_TEST(testUtf16);
	LOGUNIT_TEST(testUtf16LE);
	LOGUNIT_TEST(testUtf16BE);
	LOGUNIT_TEST_SUITE_END();
public:
	/**
	 * Resets configuration after each test.
	 */
	void tearDown()
	{
		Logger::getRootLogger()->getLoggerRepository()->resetConfiguration();
	}


	/**
	 * Test us-ascii encoding.
	 */
	void testASCII()
	{
		LoggerPtr root(Logger::getRootLogger());

		configure(root, LOG4CXX_STR("output/encoding/ascii.log"),
			LOG4CXX_STR("US-ASCII"));
		common(root);

		BinaryCompare::compare( "output/encoding/ascii.log",
			"witness/encoding/ascii.log");
	}

	/**
	 * Test iso-8859-1 encoding.
	 */
	void testLatin1()
	{
		LoggerPtr root(Logger::getRootLogger());

		configure(root, LOG4CXX_STR("output/encoding/latin1.log"),
			LOG4CXX_STR("iso-8859-1"));
		common(root);

		BinaryCompare::compare( "output/encoding/latin1.log",
			"witness/encoding/latin1.log");
	}

	/**
	 * Test utf-8 encoding.
	 */
	void testUtf8()
	{
		LoggerPtr root(Logger::getRootLogger());

		configure(root, LOG4CXX_STR("output/encoding/UTF-8.log"),
			LOG4CXX_STR("UTF-8"));
		common(root);

		BinaryCompare::compare( "output/encoding/UTF-8.log",
			"witness/encoding/UTF-8.log");
	}

	/**
	 * Test utf-16 encoding.
	 */
	void testUtf16()
	{
		LoggerPtr root(Logger::getRootLogger());

		configure(root, LOG4CXX_STR("output/encoding/UTF-16.log"),
			LOG4CXX_STR("UTF-16"));
		common(root);

		BinaryCompare::compare( "output/encoding/UTF-16.log",
			"witness/encoding/UTF-16.log");
	}

	/**
	 * Test utf-16be encoding.
	 */
	void testUtf16BE()
	{
		LoggerPtr root(Logger::getRootLogger());

		configure(root, LOG4CXX_STR("output/encoding/UTF-16BE.log"),
			LOG4CXX_STR("UTF-16BE"));
		common(root);

		BinaryCompare::compare( "output/encoding/UTF-16BE.log",
			"witness/encoding/UTF-16BE.log");
	}

	/**
	 * Test utf16-le encoding.
	 */
	void testUtf16LE()
	{
		LoggerPtr root(Logger::getRootLogger());

		configure(root, LOG4CXX_STR("output/encoding/UTF-16LE.log"),
			LOG4CXX_STR("UTF-16LE"));
		common(root);

		BinaryCompare::compare( "output/encoding/UTF-16LE.log",
			"witness/encoding/UTF-16LE.log");
	}

	/**
	 * Configure logging.
	 * @param logger logger
	 * @param filename logging file name
	 * @param encoding encoding
	 */
private:
	void configure(      LoggerPtr & logger,
		const LogString & filename,
		const LogString & encoding)
	{
		FileAppenderPtr  appender(new FileAppender());
		PatternLayoutPtr layout(new PatternLayout());
		Pool             p;

		layout->setConversionPattern(LOG4CXX_STR("%p - %m\n"));
		layout->activateOptions(p);

		appender->setAppend(false);
		appender->setEncoding(encoding);
		appender->setFile(filename);
		appender->setLayout(layout);
		appender->activateOptions(p);

		logger->addAppender(appender);
		logger->setLevel(Level::getInfo());
	}

	/**
	 * Common logging requests.
	 * @param logger logger
	 */
	void common(LoggerPtr & logger)
	{
		logger->info("Hello, World");

		// pi can be encoded in iso-8859-1
		const wchar_t pi[] = { 0x00B9, 0 };
		logger->info(pi);

		//   arbitrary, hopefully meaningless, characters from
		//     Latin, Arabic, Armenian, Bengali, CJK and Cyrillic
		const wchar_t greeting[] = { L'A', 0x0605, 0x0530, 0x986, 0x4E03, 0x400, 0 };
		logger->info(greeting);
	}
};

LOGUNIT_TEST_SUITE_REGISTRATION(EncodingTest);

#endif

