/* * 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 #include "../logunit.h" #include "../insertwide.h" #include #include #include #include #include #include #include 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);