blob: dec0ae9c439dc8ed70a029614fc9fc0d2a8e9a15 [file]
/*
* 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/log4cxx.h>
#include <ostream>
#include <iomanip>
#include "vectorappender.h"
#include <log4cxx/logmanager.h>
#include <log4cxx/simplelayout.h>
#include <log4cxx/spi/loggingevent.h>
#include "insertwide.h"
#include "logunit.h"
#include <log4cxx/stream.h>
#include <log4cxx/helpers/loglog.h>
#if LOG4CXX_CFSTRING_API
#include <CoreFoundation/CFString.h>
#endif
using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace std;
class ExceptionOnInsert
{
public:
ExceptionOnInsert()
{
}
};
//
// define an insertion operation that will throw an
// exception to test that evaluation was short
// circuited
//
template<class Elem, class Tr>
::std::basic_ostream<Elem, Tr>& operator<<(
::std::basic_ostream<Elem, Tr>&,
const ExceptionOnInsert&)
{
throw std::exception();
}
/**
Unit tests for the optional stream-like interface for log4cxx
*/
LOGUNIT_CLASS(StreamTestCase)
{
LOGUNIT_TEST_SUITE(StreamTestCase);
LOGUNIT_TEST(testSimple);
LOGUNIT_TEST(testMultiple);
LOGUNIT_TEST(testShortCircuit);
LOGUNIT_TEST_EXCEPTION(testInsertException, std::exception);
LOGUNIT_TEST(testScientific);
LOGUNIT_TEST(testPrecision);
LOGUNIT_TEST(testWidth);
#if LOG4CXX_WCHAR_T_API
LOGUNIT_TEST(testWide);
LOGUNIT_TEST(testWideAppend);
LOGUNIT_TEST(testWideWidth);
#endif
LOGUNIT_TEST(testBaseFlags);
LOGUNIT_TEST(testBasePrecisionAndWidth);
LOGUNIT_TEST(testLogStreamSimple);
LOGUNIT_TEST(testLogStreamMultiple);
LOGUNIT_TEST(testLogStreamShortCircuit);
LOGUNIT_TEST_EXCEPTION(testLogStreamInsertException, std::exception);
LOGUNIT_TEST(testLogStreamScientific);
LOGUNIT_TEST(testLogStreamPrecision);
LOGUNIT_TEST(testLogStreamWidth);
LOGUNIT_TEST(testLogStreamDelegate);
LOGUNIT_TEST(testLogStreamFormattingPersists);
LOGUNIT_TEST(testSetWidthInsert);
#if LOG4CXX_WCHAR_T_API
LOGUNIT_TEST(testWLogStreamSimple);
LOGUNIT_TEST(testWLogStreamMultiple);
LOGUNIT_TEST(testWLogStreamShortCircuit);
LOGUNIT_TEST_EXCEPTION(testWLogStreamInsertException, std::exception);
LOGUNIT_TEST(testWLogStreamScientific);
LOGUNIT_TEST(testWLogStreamPrecision);
LOGUNIT_TEST(testWLogStreamWidth);
LOGUNIT_TEST(testWLogStreamDelegate);
LOGUNIT_TEST(testWLogStreamFormattingPersists);
LOGUNIT_TEST(testWSetWidthInsert);
#endif
#if LOG4CXX_CFSTRING_API
LOGUNIT_TEST(testCFString);
LOGUNIT_TEST(testCFStringAppend);
#endif
LOGUNIT_TEST_SUITE_END();
VectorAppenderPtr vectorAppender;
#ifdef _DEBUG
struct Fixture
{
Fixture() {
helpers::LogLog::setInternalDebugging(true);
}
} suiteFixture;
#endif
public:
void setUp()
{
LoggerPtr root(Logger::getRootLogger());
LayoutPtr layout(new SimpleLayout());
vectorAppender = VectorAppenderPtr(new VectorAppender());
root->addAppender(vectorAppender);
}
void tearDown()
{
LogManager::shutdown();
}
void testSimple()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, "This is a test");
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testMultiple()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, "This is a test" << ": Details to follow");
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testShortCircuit()
{
LoggerPtr logger(Logger::getLogger("StreamTestCase.shortCircuit"));
logger->setLevel(Level::getInfo());
ExceptionOnInsert someObj;
LOG4CXX_DEBUG(logger, someObj);
LOGUNIT_ASSERT_EQUAL((size_t) 0, vectorAppender->getVector().size());
}
void testInsertException()
{
LoggerPtr logger(Logger::getLogger("StreamTestCase.insertException"));
ExceptionOnInsert someObj;
LOG4CXX_INFO(logger, someObj);
}
void testScientific()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, std::scientific << 0.000001115);
auto events = vectorAppender->getVector();
LOGUNIT_ASSERT_EQUAL((size_t) 1, events.size());
LogString msg(events.front()->getMessage());
LOGUNIT_ASSERT(msg.find(LOG4CXX_STR("e-")) != LogString::npos ||
msg.find(LOG4CXX_STR("E-")) != LogString::npos);
}
void testPrecision()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, std::setprecision(4) << 1.000001);
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT(msg.find(LOG4CXX_STR("1.00000")) == LogString::npos);
}
void testWidth()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, '[' << std::fixed << std::setprecision(2) << std::setw(7) << std::right << std::setfill('_') << 10.0 << ']');
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT_EQUAL(LogString(LOG4CXX_STR("[__10.00]")), msg);
}
void testBaseFlags()
{
logstream base1(Logger::getRootLogger(), Level::getInfo());
logstream base2(Logger::getRootLogger(), Level::getInfo());
base1 << std::boolalpha;
base2 << std::noboolalpha;
std::ostringstream os1a, os1b, os2a, os2b;
os1a << std::boolalpha;
int fillchar;
if (base1.set_stream_state(os1b, fillchar))
{
os1b.fill(fillchar);
}
LOGUNIT_ASSERT_EQUAL(os1a.flags(), os1b.flags());
os2a << std::noboolalpha;
if (base2.set_stream_state(os2b, fillchar))
{
os2b.fill(fillchar);
}
LOGUNIT_ASSERT_EQUAL(os2a.flags(), os2b.flags());
}
void testBasePrecisionAndWidth()
{
logstream base(Logger::getRootLogger(), Level::getInfo());
base.precision(2);
base.width(5);
std::ostringstream os1, os2;
os1.precision(2);
os1.width(5);
os1 << 3.1415926;
int fillchar;
if (base.set_stream_state(os2, fillchar))
{
os2.fill(fillchar);
}
os2 << 3.1415926;
string expected(os1.str());
string actual(os2.str());
LOGUNIT_ASSERT_EQUAL(expected, actual);
}
void testLogStreamSimple()
{
logstream root(Logger::getRootLogger(), Level::getInfo());
root << std::string("This is a test") << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testLogStreamMultiple()
{
logstream root(Logger::getRootLogger(), Level::getInfo());
root << std::string("This is a test") << std::string(": Details to follow") << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testLogStreamShortCircuit()
{
LoggerPtr logger(Logger::getLogger("StreamTestCase.shortCircuit"));
logger->setLevel(Level::getInfo());
logstream os(logger, Level::getDebug());
ExceptionOnInsert someObj;
os << someObj << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 0, vectorAppender->getVector().size());
}
void testLogStreamInsertException()
{
LoggerPtr logger(Logger::getLogger("StreamTestCase.insertException"));
ExceptionOnInsert someObj;
logstream os(logger, Level::getInfo());
os << someObj << LOG4CXX_ENDMSG;
}
void testLogStreamScientific()
{
LoggerPtr root(Logger::getRootLogger());
logstream os(root, Level::getInfo());
os << std::scientific << 0.000001115 << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT(msg.find(LOG4CXX_STR("e-")) != LogString::npos ||
msg.find(LOG4CXX_STR("E-")) != LogString::npos);
}
void testLogStreamPrecision()
{
LoggerPtr root(Logger::getRootLogger());
logstream os(root, Level::getInfo());
os << std::setprecision(4) << 1.000001 << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT(msg.find(LOG4CXX_STR("1.00000")) == LogString::npos);
}
void testLogStreamWidth()
{
LoggerPtr root(Logger::getRootLogger());
logstream os(root, Level::getInfo());
os << '[' << std::fixed << std::setprecision(2) << std::setw(7) << std::right << std::setfill('_') << 10.0 << ']' << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT_EQUAL(LogString(LOG4CXX_STR("[__10.00]")), msg);
}
void report(std::ostream & os)
{
os << "This just in: \n";
os << "Use logstream in places that expect a std::ostream.\n";
}
void testLogStreamDelegate()
{
logstream root(Logger::getRootLogger(), Level::getInfo());
report(root);
root << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testLogStreamFormattingPersists()
{
LoggerPtr root(Logger::getRootLogger());
root->setLevel(Level::getInfo());
logstream os(root, Level::getDebug());
os << std::hex << 20 << LOG4CXX_ENDMSG;
os << Level::getInfo() << 16 << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT_EQUAL(LogString(LOG4CXX_STR("10")), msg);
}
void testSetWidthInsert()
{
LoggerPtr root(Logger::getRootLogger());
root->setLevel(Level::getInfo());
logstream os(root, Level::getInfo());
os << std::setw(5);
LOGUNIT_ASSERT_EQUAL(5, os.width());
}
#if LOG4CXX_WCHAR_T_API
void testWide()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, L"This is a test");
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testWideAppend()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, L"This is a test" << L": Details to follow");
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testWideWidth()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, L'[' << std::fixed << std::setprecision(2) << std::setw(7) << std::right << std::setfill(L'_') << 10.0 << L"]");
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT_EQUAL(LogString(LOG4CXX_STR("[__10.00]")), msg);
}
void testWLogStreamSimple()
{
wlogstream root(Logger::getRootLogger(), Level::getInfo());
root << L"This is a test" << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testWLogStreamMultiple()
{
wlogstream root(Logger::getRootLogger(), Level::getInfo());
root << L"This is a test" << L": Details to follow" << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testWLogStreamShortCircuit()
{
LoggerPtr logger(Logger::getLogger("StreamTestCase.shortCircuit"));
logger->setLevel(Level::getInfo());
wlogstream os(logger, Level::getDebug());
ExceptionOnInsert someObj;
os << someObj << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 0, vectorAppender->getVector().size());
}
void testWLogStreamInsertException()
{
LoggerPtr logger(Logger::getLogger("StreamTestCase.insertException"));
ExceptionOnInsert someObj;
wlogstream os(logger, Level::getInfo());
os << someObj << LOG4CXX_ENDMSG;
}
void testWLogStreamScientific()
{
LoggerPtr root(Logger::getRootLogger());
wlogstream os(root, Level::getInfo());
os << std::scientific << 0.000001115 << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT(msg.find(LOG4CXX_STR("e-")) != LogString::npos ||
msg.find(LOG4CXX_STR("E-")) != LogString::npos);
}
void testWLogStreamPrecision()
{
LoggerPtr root(Logger::getRootLogger());
wlogstream os(root, Level::getInfo());
os << std::setprecision(4) << 1.000001 << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT(msg.find(LOG4CXX_STR("1.00000")) == LogString::npos);
}
void testWLogStreamWidth()
{
LoggerPtr root(Logger::getRootLogger());
wlogstream os(root, Level::getInfo());
os << L"[" << std::fixed << std::setprecision(2) << std::setw(7) << std::right << std::setfill(L'_') << 10.0 << L"]" << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT_EQUAL(LogString(LOG4CXX_STR("[__10.00]")), msg);
}
void wreport(std::basic_ostream<wchar_t>& os)
{
os << L"This just in: \n";
os << L"Use logstream in places that expect a std::ostream.\n";
}
void testWLogStreamDelegate()
{
wlogstream root(Logger::getRootLogger(), Level::getInfo());
wreport(root);
root << LOG4CXX_ENDMSG;
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testWLogStreamFormattingPersists()
{
LoggerPtr root(Logger::getRootLogger());
root->setLevel(Level::getInfo());
wlogstream os(root, Level::getDebug());
os << std::hex << 20 << LOG4CXX_ENDMSG;
os << Level::getInfo() << 16 << LOG4CXX_ENDMSG;
spi::LoggingEventPtr event(vectorAppender->getVector()[0]);
LogString msg(event->getMessage());
LOGUNIT_ASSERT_EQUAL(LogString(LOG4CXX_STR("10")), msg);
}
void testWSetWidthInsert()
{
LoggerPtr root(Logger::getRootLogger());
root->setLevel(Level::getInfo());
wlogstream os(root, Level::getInfo());
os << std::setw(5);
LOGUNIT_ASSERT_EQUAL(5, os.width());
}
#endif
#if LOG4CXX_CFSTRING_API
void testCFString()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, CFSTR("This is a test"));
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
void testCFStringAppend()
{
LoggerPtr root(Logger::getRootLogger());
LOG4CXX_INFO(root, CFSTR("This is a test") << CFSTR(": Details to follow"));
LOGUNIT_ASSERT_EQUAL((size_t) 1, vectorAppender->getVector().size());
}
#endif
};
LOGUNIT_TEST_SUITE_REGISTRATION(StreamTestCase);
#if !LOG4CXX_USE_GLOBAL_SCOPE_TEMPLATE
//
// The following code tests compilation errors
// around bug LOGCXX-150 and is not intended to be executed.
// Skipped for VC6 since it can't handle having the
// templated operator<< in class scope.s
namespace foo
{
class Bar
{
void fn();
};
std::ostream& operator<<(std::ostream& o, Bar const& b)
{
return o << "Bar";
}
}
using namespace foo;
namespace
{
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("foo"));
log4cxx::logstream lout(logger, log4cxx::Level::getDebug());
}
void Bar::fn()
{
lout << "hi" << LOG4CXX_ENDMSG;
}
#endif