blob: 214d21029a5d4a919c724d5645f7937a66f512c0 [file] [log] [blame]
/*
* 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/helpers/charsetencoder.h>
#include "../logunit.h"
#include "../insertwide.h"
#include <log4cxx/helpers/bytebuffer.h>
#include <apr.h>
#include <apr_atomic.h>
#include <condition_variable>
using namespace log4cxx;
using namespace log4cxx::helpers;
LOGUNIT_CLASS(CharsetEncoderTestCase)
{
LOGUNIT_TEST_SUITE(CharsetEncoderTestCase);
LOGUNIT_TEST(encode1);
LOGUNIT_TEST(encode2);
LOGUNIT_TEST(encode3);
LOGUNIT_TEST(encode4);
#if APR_HAS_THREADS
LOGUNIT_TEST(thread1);
#endif
LOGUNIT_TEST_SUITE_END();
enum { BUFSIZE = 256 };
public:
void encode1()
{
const LogString greeting(LOG4CXX_STR("Hello, World"));
CharsetEncoderPtr enc(CharsetEncoder::getEncoder(LOG4CXX_STR("US-ASCII")));
char buf[BUFSIZE];
ByteBuffer out(buf, BUFSIZE);
LogString::const_iterator iter = greeting.begin();
log4cxx_status_t stat = enc->encode(greeting, iter, out);
LOGUNIT_ASSERT_EQUAL(APR_SUCCESS, stat);
LOGUNIT_ASSERT(iter == greeting.end());
stat = enc->encode(greeting, iter, out);
LOGUNIT_ASSERT_EQUAL(APR_SUCCESS, stat);
LOGUNIT_ASSERT_EQUAL((size_t) 12, out.position());
out.flip();
std::string encoded((const char*) out.data(), out.limit());
LOGUNIT_ASSERT_EQUAL((std::string) "Hello, World", encoded);
LOGUNIT_ASSERT(iter == greeting.end());
}
void encode2()
{
LogString greeting(BUFSIZE - 3, LOG4CXX_STR('A'));
greeting.append(LOG4CXX_STR("Hello"));
CharsetEncoderPtr enc(CharsetEncoder::getEncoder(LOG4CXX_STR("US-ASCII")));
char buf[BUFSIZE];
ByteBuffer out(buf, BUFSIZE);
LogString::const_iterator iter = greeting.begin();
log4cxx_status_t stat = enc->encode(greeting, iter, out);
LOGUNIT_ASSERT_EQUAL(APR_SUCCESS, stat);
LOGUNIT_ASSERT_EQUAL((size_t) 0, out.remaining());
LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR('o'), *(iter + 1));
out.flip();
std::string encoded((char*) out.data(), out.limit());
out.clear();
stat = enc->encode(greeting, iter, out);
LOGUNIT_ASSERT_EQUAL(APR_SUCCESS, stat);
LOGUNIT_ASSERT_EQUAL((size_t) 2, out.position());
LOGUNIT_ASSERT(iter == greeting.end());
stat = enc->encode(greeting, iter, out);
out.flip();
LOGUNIT_ASSERT_EQUAL(APR_SUCCESS, stat);
encoded.append(out.data(), out.limit());
std::string manyAs(BUFSIZE - 3, 'A');
LOGUNIT_ASSERT_EQUAL(manyAs, encoded.substr(0, BUFSIZE - 3));
LOGUNIT_ASSERT_EQUAL(std::string("Hello"), encoded.substr(BUFSIZE - 3));
}
void encode3()
{
#if LOG4CXX_LOGCHAR_IS_WCHAR || LOG4CXX_LOGCHAR_IS_UNICHAR
// arbitrary, hopefully meaningless, characters from
// Latin, Arabic, Armenian, Bengali, CJK and Cyrillic
const logchar greet[] = { L'A', 0x0605, 0x0530, 0x986, 0x4E03, 0x400, 0 };
#endif
#if LOG4CXX_LOGCHAR_IS_UTF8
const char greet[] = { 'A',
(char) 0xD8, (char) 0x85,
(char) 0xD4, (char) 0xB0,
(char) 0xE0, (char) 0xA6, (char) 0x86,
(char) 0xE4, (char) 0xB8, (char) 0x83,
(char) 0xD0, (char) 0x80,
0
};
#endif
LogString greeting(greet);
CharsetEncoderPtr enc(CharsetEncoder::getEncoder(LOG4CXX_STR("US-ASCII")));
char buf[BUFSIZE];
ByteBuffer out(buf, BUFSIZE);
LogString::const_iterator iter = greeting.begin();
log4cxx_status_t stat = enc->encode(greeting, iter, out);
out.flip();
LOGUNIT_ASSERT_EQUAL(true, CharsetEncoder::isError(stat));
LOGUNIT_ASSERT_EQUAL((size_t) 1, out.limit());
LOGUNIT_ASSERT_EQUAL(greet[1], *iter);
LOGUNIT_ASSERT_EQUAL('A', out.data()[0]);
}
void encode4()
{
const char utf8_greet[] = { 'A',
(char) 0xD8, (char) 0x85,
(char) 0xD4, (char) 0xB0,
(char) 0xE0, (char) 0xA6, (char) 0x86,
(char) 0xE4, (char) 0xB8, (char) 0x83,
(char) 0xD0, (char) 0x80,
0
};
#if LOG4CXX_LOGCHAR_IS_WCHAR || LOG4CXX_LOGCHAR_IS_UNICHAR
// arbitrary, hopefully meaningless, characters from
// Latin, Arabic, Armenian, Bengali, CJK and Cyrillic
const logchar greet[] = { L'A', 0x0605, 0x0530, 0x986, 0x4E03, 0x400, 0 };
#endif
#if LOG4CXX_LOGCHAR_IS_UTF8
const logchar* greet = utf8_greet;
#endif
LogString greeting(greet);
CharsetEncoderPtr enc(CharsetEncoder::getEncoder(LOG4CXX_STR("UTF-8")));
char buf[BUFSIZE];
ByteBuffer out(buf, BUFSIZE);
LogString::const_iterator iter = greeting.begin();
log4cxx_status_t stat = enc->encode(greeting, iter, out);
LOGUNIT_ASSERT_EQUAL(false, CharsetEncoder::isError(stat));
stat = enc->encode(greeting, iter, out);
LOGUNIT_ASSERT_EQUAL(false, CharsetEncoder::isError(stat));
out.flip();
LOGUNIT_ASSERT_EQUAL((size_t) 13, out.limit());
for (size_t i = 0; i < out.limit(); i++)
{
LOGUNIT_ASSERT_EQUAL((int) utf8_greet[i], (int) out.data()[i]);
}
LOGUNIT_ASSERT(iter == greeting.end());
}
#if APR_HAS_THREADS
class ThreadPackage
{
public:
ThreadPackage(CharsetEncoderPtr& enc, int repetitions) :
p(), passCount(0), failCount(0), enc(enc), repetitions(repetitions)
{
}
void await()
{
log4cxx::unique_lock<log4cxx::mutex> sync(lock);
condition.wait(sync);
}
void signalAll()
{
log4cxx::unique_lock<log4cxx::mutex> sync(lock);
condition.notify_all();
}
void fail()
{
apr_atomic_inc32(&failCount);
}
void pass()
{
apr_atomic_inc32(&passCount);
}
apr_uint32_t getFail()
{
return apr_atomic_read32(&failCount);
}
apr_uint32_t getPass()
{
return apr_atomic_read32(&passCount);
}
int getRepetitions()
{
return repetitions;
}
CharsetEncoderPtr& getEncoder()
{
return enc;
}
void run()
{
#if LOG4CXX_LOGCHAR_IS_UTF8
const logchar greet[] = { 'H', 'e', 'l', 'l', 'o', ' ',
(char) 0xC2, (char) 0xA2, // cent sign
(char) 0xC2, (char) 0xA9, // copyright
(char) 0xc3, (char) 0xb4, // latin small letter o with circumflex
0
};
#endif
#if LOG4CXX_LOGCHAR_IS_WCHAR || LOG4CXX_LOGCHAR_IS_UNICHAR
// arbitrary, hopefully meaningless, characters from
// Latin, Arabic, Armenian, Bengali, CJK and Cyrillic
const logchar greet[] = { L'H', L'e', L'l', L'l', L'o', L' ',
0x00A2, 0x00A9, 0x00F4, 0
};
#endif
const char expected[] = { 'H', 'e', 'l', 'l', 'o', ' ',
(char) 0x00A2, (char) 0x00A9, (char) 0x00F4
};
LogString greeting(greet);
await();
for (int i = 0; i < getRepetitions(); i++)
{
bool pass = true;
char buf[BUFSIZE];
ByteBuffer out(buf, BUFSIZE);
LogString::const_iterator iter = greeting.begin();
log4cxx_status_t stat = getEncoder()->encode(greeting, iter, out);
pass = (false == CharsetEncoder::isError(stat));
if (pass)
{
stat = getEncoder()->encode(greeting, iter, out);
pass = (false == CharsetEncoder::isError(stat));
if (pass)
{
out.flip();
pass = (sizeof(expected) == out.limit());
for (size_t i = 0; i < out.limit() && pass; i++)
{
pass = (expected[i] == out.data()[i]);
}
pass = pass && (iter == greeting.end());
}
}
if (pass)
{
ThreadPackage::pass();
}
else
{
fail();
}
}
}
private:
ThreadPackage(const ThreadPackage&);
ThreadPackage& operator=(ThreadPackage&);
Pool p;
mutex lock;
condition_variable condition;
volatile apr_uint32_t passCount;
volatile apr_uint32_t failCount;
CharsetEncoderPtr enc;
int repetitions;
};
void thread1()
{
enum { THREAD_COUNT = 10, THREAD_REPS = 10000 };
log4cxx::thread threads[THREAD_COUNT];
CharsetEncoderPtr enc(CharsetEncoder::getEncoder(LOG4CXX_STR("ISO-8859-1")));
ThreadPackage* package = new ThreadPackage(enc, THREAD_REPS);
{
for (int i = 0; i < THREAD_COUNT; i++)
{
threads[i] = log4cxx::thread(&ThreadPackage::run, package);
}
}
//
// give time for all threads to be launched so
// we don't signal before everybody is waiting.
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
package->signalAll();
for (int i = 0; i < THREAD_COUNT; i++)
{
threads[i].join();
}
LOGUNIT_ASSERT_EQUAL((apr_uint32_t) 0, package->getFail());
LOGUNIT_ASSERT_EQUAL((apr_uint32_t) THREAD_COUNT * THREAD_REPS, package->getPass());
delete package;
}
#endif
};
LOGUNIT_TEST_SUITE_REGISTRATION(CharsetEncoderTestCase);