diff options
Diffstat (limited to 'src/test/cpp/helpers/charsetencodertestcase.cpp')
-rw-r--r-- | src/test/cpp/helpers/charsetencodertestcase.cpp | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/test/cpp/helpers/charsetencodertestcase.cpp b/src/test/cpp/helpers/charsetencodertestcase.cpp new file mode 100644 index 0000000..74af926 --- /dev/null +++ b/src/test/cpp/helpers/charsetencodertestcase.cpp @@ -0,0 +1,302 @@ +/* + * 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 <log4cxx/helpers/thread.h> +#include <log4cxx/helpers/mutex.h> +#include <log4cxx/helpers/condition.h> +#include <log4cxx/helpers/synchronized.h> +#include <apr.h> +#include <apr_atomic.h> + + +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(), lock(p), condition(p), passCount(0), failCount(0), enc(enc), repetitions(repetitions) { + } + + void await() { + synchronized sync(lock); + condition.await(lock); + } + + void signalAll() { + synchronized sync(lock); + condition.signalAll(); + } + + 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; + } + + private: + ThreadPackage(const ThreadPackage&); + ThreadPackage& operator=(ThreadPackage&); + Pool p; + Mutex lock; + Condition condition; + volatile apr_uint32_t passCount; + volatile apr_uint32_t failCount; + CharsetEncoderPtr enc; + int repetitions; + }; + + static void* LOG4CXX_THREAD_FUNC thread1Action(apr_thread_t* /* thread */, void* data) { + ThreadPackage* package = (ThreadPackage*) data; +#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); + + package->await(); + for(int i = 0; i < package->getRepetitions(); i++) { + bool pass = true; + char buf[BUFSIZE]; + ByteBuffer out(buf, BUFSIZE); + LogString::const_iterator iter = greeting.begin(); + log4cxx_status_t stat = package->getEncoder()->encode(greeting, iter, out); + pass = (false == CharsetEncoder::isError(stat)); + if (pass) { + stat = package->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) { + package->pass(); + } else { + package->fail(); + } + } + return 0; + } + + void thread1() { + enum { THREAD_COUNT = 10, THREAD_REPS = 10000 }; + 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].run(thread1Action, package); + } } + // + // give time for all threads to be launched so + // we don't signal before everybody is waiting. + Thread::sleep(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); |