blob: e0c45d179c7bf164dfd1d68edeb2b79d185fb1e5 [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/file.h>
#include "logunit.h"
#include "insertwide.h"
#include <log4cxx/helpers/pool.h>
#include <apr_errno.h>
#include <log4cxx/helpers/exception.h>
#include <log4cxx/helpers/fileinputstream.h>
#include <log4cxx/helpers/outputstreamwriter.h>
#include <log4cxx/helpers/fileoutputstream.h>
#include <log4cxx/helpers/inputstreamreader.h>
#include <log4cxx/helpers/fileinputstream.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/bytebuffer.h>
#include <log4cxx/helpers/transcoder.h>
#if LOG4CXX_CFSTRING_API
#include <CoreFoundation/CFString.h>
#endif
using namespace log4cxx;
using namespace log4cxx::helpers;
LOGUNIT_CLASS(FileTestCase)
{
LOGUNIT_TEST_SUITE(FileTestCase);
LOGUNIT_TEST(defaultConstructor);
LOGUNIT_TEST(defaultExists);
LOGUNIT_TEST(defaultRead);
LOGUNIT_TEST(propertyRead);
LOGUNIT_TEST(propertyExists);
LOGUNIT_TEST(fileWrite1);
#if LOG4CXX_WCHAR_T_API
LOGUNIT_TEST(wcharConstructor);
#endif
#if LOG4CXX_UNICHAR_API
LOGUNIT_TEST(unicharConstructor);
#endif
#if LOG4CXX_CFSTRING_API
LOGUNIT_TEST(cfstringConstructor);
#endif
LOGUNIT_TEST(copyConstructor);
LOGUNIT_TEST(assignment);
LOGUNIT_TEST(deleteBackslashedFileName);
LOGUNIT_TEST(testSplitMultibyteUtf8);
LOGUNIT_TEST(testInvalidUtf8);
LOGUNIT_TEST_SUITE_END();
#ifdef _DEBUG
struct Fixture
{
Fixture() {
helpers::LogLog::setInternalDebugging(true);
}
} suiteFixture;
#endif
public:
void defaultConstructor()
{
File defFile;
LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR(""), defFile.getPath());
}
void defaultExists()
{
File defFile;
Pool pool;
bool exists = defFile.exists(pool);
LOGUNIT_ASSERT_EQUAL(false, exists);
}
// check default constructor. read() throws an exception
// if no file name was given.
void defaultRead()
{
File defFile;
Pool pool;
try
{
InputStreamPtr defInput = FileInputStreamPtr(new FileInputStream(defFile));
InputStreamReaderPtr inputReader = InputStreamReaderPtr(new InputStreamReader(defInput));
LogString contents(inputReader->read(pool));
LOGUNIT_ASSERT(false);
}
catch (IOException& ex)
{
LOG4CXX_DECODE_CHAR(msg, ex.what());
LogLog::debug(msg);
}
}
#if LOG4CXX_WCHAR_T_API
void wcharConstructor()
{
File propFile(L"input/patternLayout1.properties");
Pool pool;
bool exists = propFile.exists(pool);
LOGUNIT_ASSERT_EQUAL(true, exists);
}
#endif
#if LOG4CXX_UNICHAR_API
void unicharConstructor()
{
const log4cxx::UniChar filename[] = { 'i', 'n', 'p', 'u', 't', '/',
'p', 'a', 't', 't', 'e', 'r', 'n', 'L', 'a', 'y', 'o', 'u', 't', '1', '.',
'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's', 0
};
File propFile(filename);
Pool pool;
bool exists = propFile.exists(pool);
LOGUNIT_ASSERT_EQUAL(true, exists);
}
#endif
#if LOG4CXX_CFSTRING_API
void cfstringConstructor()
{
File propFile(CFSTR("input/patternLayout1.properties"));
Pool pool;
bool exists = propFile.exists(pool);
LOGUNIT_ASSERT_EQUAL(true, exists);
}
#endif
void copyConstructor()
{
File propFile("input/patternLayout1.properties");
File copy(propFile);
Pool pool;
bool exists = copy.exists(pool);
LOGUNIT_ASSERT_EQUAL(true, exists);
}
void assignment()
{
File propFile("input/patternLayout1.properties");
File copy = propFile;
Pool pool;
bool exists = copy.exists(pool);
LOGUNIT_ASSERT_EQUAL(true, exists);
}
void propertyRead()
{
File propFile("input/patternLayout1.properties");
Pool pool;
InputStreamPtr propStream = FileInputStreamPtr(new FileInputStream(propFile));
InputStreamReaderPtr propReader = InputStreamReaderPtr(new InputStreamReader(propStream));
LogString props(propReader->read(pool));
LogString line1(LOG4CXX_STR("# Licensed to the Apache Software Foundation (ASF) under one or more"));
LOGUNIT_ASSERT_EQUAL(line1, props.substr(0, line1.length()));
}
void propertyExists()
{
File propFile("input/patternLayout1.properties");
Pool pool;
bool exists = propFile.exists(pool);
LOGUNIT_ASSERT_EQUAL(true, exists);
}
void fileWrite1()
{
OutputStreamPtr fos = FileOutputStreamPtr(
new FileOutputStream(LOG4CXX_STR("output/fileWrite1.txt")));
OutputStreamWriterPtr osw = OutputStreamWriterPtr(new OutputStreamWriter(fos));
Pool pool;
LogString greeting(LOG4CXX_STR("Hello, World"));
greeting.append(LOG4CXX_EOL);
osw->write(greeting, pool);
InputStreamPtr is = FileInputStreamPtr(
new FileInputStream(LOG4CXX_STR("output/fileWrite1.txt")));
InputStreamReaderPtr isr = InputStreamReaderPtr(new InputStreamReader(is));
LogString reply = isr->read(pool);
LOGUNIT_ASSERT_EQUAL(greeting, reply);
}
/**
* Tests conversion of backslash containing file names.
* Would cause infinite loop due to bug LOGCXX-105.
*/
void deleteBackslashedFileName()
{
File file("output\\bogus.txt");
Pool pool;
/*bool deleted = */file.deleteFile(pool);
}
class MockInputStream : public InputStream
{
ByteBuffer m_data;
public:
MockInputStream(const char* data, size_t charCount)
: m_data(const_cast<char*>(data), charCount)
{}
int read(ByteBuffer& dst) override
{
auto availableBytes = m_data.remaining();
if (availableBytes < 1)
return -1;
int count = 0;
for (auto p = m_data.current(); count < availableBytes && dst.put(*p); ++p)
++count;
m_data.increment_position(count);
return count;
}
void close() override {}
};
/**
* Tests behavior when a multibyte UTF-8 sequence occurs on a read boundary
*/
void testSplitMultibyteUtf8()
{
Pool p;
// InputStreamReader uses a buffer of size 4096
std::string input( 4094, 'A' );
// räksmörgås.josefsson.org
input.append("\162\303\244\153\163\155\303\266\162\147\303\245\163\056\152\157\163\145\146\163\163\157\156\056\157\162\147");
InputStreamReader reader(std::make_shared<MockInputStream>(input.c_str(), input.size()), CharsetDecoder::getUTF8Decoder());
auto contentLS = reader.read(p);
LOG4CXX_ENCODE_CHAR(content, contentLS);
LOGUNIT_ASSERT_EQUAL(input, content);
}
/**
* Tests behavior given an incomplete multibyte UTF-8 sequence in the input
*/
void testInvalidUtf8()
{
Pool p;
// 0xC2 is a generic start byte for a 2-byte sequence in UTF-8.
char input[] = { 'A', (char)0xC2, 'B', 'C', 0 };
InputStreamReader reader(std::make_shared<MockInputStream>(input, 4), CharsetDecoder::getUTF8Decoder());
try
{
reader.read(p);
LOGUNIT_ASSERT(false);
}
catch (const Exception& ex)
{
LOG4CXX_DECODE_CHAR(msg, ex.what());
LogLog::debug(msg);
}
}
};
LOGUNIT_TEST_SUITE_REGISTRATION(FileTestCase);