From 455fb8e13f478fb247fbb2ceefe2b8bb0e638f80 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Thu, 3 Aug 2023 09:52:42 +1000 Subject: [PATCH] Allow CFString code testing on non-Apple systems (#244) * Add CFString tests to transcodertests --- src/main/CMakeLists.txt | 8 +++ src/main/cpp/CMakeLists.txt | 4 -- src/main/cpp/messagebuffer.cpp | 2 +- src/main/mock-apple/CFString.cpp | 70 +++++++++++++++++++ src/main/mock-apple/CMakeLists.txt | 25 +++++++ src/main/mock-apple/CoreFoundation/CFString.h | 24 +++++++ src/test/cpp/CMakeLists.txt | 6 +- src/test/cpp/helpers/transcodertestcase.cpp | 34 ++++++++- 8 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 src/main/mock-apple/CFString.cpp create mode 100644 src/main/mock-apple/CMakeLists.txt create mode 100644 src/main/mock-apple/CoreFoundation/CFString.h diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 3c3fc6414..0fa790489 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -26,6 +26,14 @@ target_include_directories(log4cxx PUBLIC $ ) +if(LOG4CXX_CFSTRING) + if(APPLE) + target_link_libraries(log4cxx PUBLIC "-framework CoreFoundation") + else() + add_subdirectory(mock-apple) + endif() +endif() + if(LOG4CXX_QT_SUPPORT) target_include_directories(log4cxx-qt PUBLIC $ diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt index be187a7bd..16419ffed 100644 --- a/src/main/cpp/CMakeLists.txt +++ b/src/main/cpp/CMakeLists.txt @@ -216,10 +216,6 @@ if(${ENABLE_FMT_LAYOUT}) target_link_libraries(log4cxx PUBLIC fmt::fmt) endif() -if (LOG4CXX_CFSTRING) - target_link_libraries(log4cxx PRIVATE "-framework CoreFoundation") -endif() - if(LOG4CXX_ABI_CHECK) message("Getting dependencies for ABI compatability check...") # Get the latest version of abi-dumper and abi-compliance-checker diff --git a/src/main/cpp/messagebuffer.cpp b/src/main/cpp/messagebuffer.cpp index aec85f014..6972dc703 100644 --- a/src/main/cpp/messagebuffer.cpp +++ b/src/main/cpp/messagebuffer.cpp @@ -788,7 +788,7 @@ CharMessageBuffer& CharMessageBuffer::operator<<(const CFStringRef& msg) } else { - m_priv->buf.append(&tmp[0], tmp.size()); + m_priv->buf.append(tmp); } return *this; } diff --git a/src/main/mock-apple/CFString.cpp b/src/main/mock-apple/CFString.cpp new file mode 100644 index 000000000..41c440171 --- /dev/null +++ b/src/main/mock-apple/CFString.cpp @@ -0,0 +1,70 @@ +/* Mocked CFString implementation +*/ +#include "CoreFoundation/CFString.h" +#include +#include + +namespace { +int throw_out_of_mem(int status) +{ + throw std::bad_alloc(); + return status; +} +apr_pool_t* getStringPool() +{ + static struct cfstring_pool + { + apr_pool_t* ptr = 0; + cfstring_pool() + { + apr_pool_create_core_ex(&ptr, throw_out_of_mem, NULL); + } + ~cfstring_pool() + { + apr_pool_destroy(ptr); + } + } pool; + return pool.ptr; +} +} // namespace + +extern "C" { + +CFRange CFRangeMake(CFIndex loc, CFIndex len) { + CFRange result; + result.location = loc; + result.length = len; + return result; +} + +CFIndex CFStringGetLength(CFStringRef theString) { + UniChar* data = (UniChar*)theString; + CFIndex result = 0; + while (data[result]) + ++result; + return result; +} +void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer) { + UniChar* data = (UniChar*)theString; + CFIndex index = 0; + while (index < range.length) { + *buffer = data[range.location + index]; + ++index; + ++buffer; + } +} +CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars) { + UniChar* result = (UniChar*)apr_palloc(getStringPool(), (numChars + 1) * sizeof(UniChar)); + result[numChars] = 0; + for (UniChar* p = result; 0 < numChars; --numChars) + *p++ = *chars++; + return (CFStringRef)result; +} +CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding) { + UniChar* result = (UniChar*)apr_palloc(getStringPool(), (strlen(cStr) + 1) * sizeof(UniChar)); + for (UniChar *p = result; *p++ = *cStr++;) + ; + return (CFStringRef)result; +} + +} // extern "C" diff --git a/src/main/mock-apple/CMakeLists.txt b/src/main/mock-apple/CMakeLists.txt new file mode 100644 index 000000000..2c94fde7b --- /dev/null +++ b/src/main/mock-apple/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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. +# + +# Build the MockCoreFoundation library +add_library(MockCoreFoundation STATIC CFString.cpp) +target_compile_definitions(MockCoreFoundation PRIVATE ${APR_COMPILE_DEFINITIONS}) +target_include_directories(MockCoreFoundation INTERFACE PRIVATE ${APR_INCLUDE_DIR}) + +# Add to log4cxx as a dependency +target_link_libraries(log4cxx PRIVATE MockCoreFoundation) +target_include_directories(log4cxx INTERFACE PRIVATE $) diff --git a/src/main/mock-apple/CoreFoundation/CFString.h b/src/main/mock-apple/CoreFoundation/CFString.h new file mode 100644 index 000000000..23cd54e3e --- /dev/null +++ b/src/main/mock-apple/CoreFoundation/CFString.h @@ -0,0 +1,24 @@ +/* Mocked CFString.h +*/ +#include +#if !defined(__COREFOUNDATION_CFSTRING__) +#define __COREFOUNDATION_CFSTRING__ 1 +extern "C" { +typedef unsigned short UniChar; +typedef long CFIndex; +typedef struct __CFRange { + CFIndex location; + CFIndex length; +} CFRange; +typedef const struct __CFString* CFStringRef; +typedef const struct __CFAllocator* CFAllocatorRef; +typedef uint32_t CFStringEncoding; +CFRange CFRangeMake(CFIndex loc, CFIndex len); +CFIndex CFStringGetLength(CFStringRef theString); +void CFStringGetCharacters(CFStringRef theString, CFRange range, UniChar *buffer); +CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars); +CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding); +#define kCFAllocatorDefault 0 +#define CFSTR(cStr) CFStringCreateWithCString(kCFAllocatorDefault, cStr, 0) +} +#endif /* ! __COREFOUNDATION_CFSTRING__ */ diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt index 3b66d1c51..cce614d3a 100644 --- a/src/test/cpp/CMakeLists.txt +++ b/src/test/cpp/CMakeLists.txt @@ -105,12 +105,16 @@ endif() get_filename_component(UNIT_TEST_WORKING_DIR ../resources ABSOLUTE) if(LOG4CXX_CFSTRING) - set(CFSTR_TESTS filetestcase messagebuffertest leveltestcase streamtestcase) + set(CFSTR_TESTS filetestcase messagebuffertest leveltestcase streamtestcase transcodertestcase) endif() foreach(testName IN LISTS ALL_LOG4CXX_TESTS) if (${testName} IN_LIST CFSTR_TESTS) + if(APPLE) target_compile_options(${testName} PRIVATE "-fconstant-cfstrings") target_link_libraries(${testName} PRIVATE "-framework CoreFoundation") + else() + target_link_libraries(${testName} PRIVATE MockCoreFoundation) + endif() endif() target_compile_definitions(${testName} PRIVATE ${TEST_COMPILE_DEFINITIONS} ${LOG4CXX_COMPILE_DEFINITIONS} ${APR_COMPILE_DEFINITIONS} ${APR_UTIL_COMPILE_DEFINITIONS} ) target_include_directories(${testName} PRIVATE ${CMAKE_CURRENT_LIST_DIR} $) diff --git a/src/test/cpp/helpers/transcodertestcase.cpp b/src/test/cpp/helpers/transcodertestcase.cpp index e80629980..23a5caa52 100644 --- a/src/test/cpp/helpers/transcodertestcase.cpp +++ b/src/test/cpp/helpers/transcodertestcase.cpp @@ -19,6 +19,9 @@ #include "../insertwide.h" #include "../logunit.h" +#if LOG4CXX_CFSTRING_API + #include +#endif using namespace log4cxx; using namespace log4cxx::helpers; @@ -34,6 +37,9 @@ LOGUNIT_CLASS(TranscoderTestCase) LOGUNIT_TEST(decode3); #if LOG4CXX_WCHAR_T_API LOGUNIT_TEST(decode4); +#endif +#if LOG4CXX_CFSTRING_API + LOGUNIT_TEST(decode5); #endif LOGUNIT_TEST(decode7); LOGUNIT_TEST(decode8); @@ -50,6 +56,9 @@ LOGUNIT_CLASS(TranscoderTestCase) LOGUNIT_TEST(encode5); #endif LOGUNIT_TEST(encode6); +#if LOG4CXX_CFSTRING_API + LOGUNIT_TEST(encode7); +#endif LOGUNIT_TEST(testDecodeUTF8_1); LOGUNIT_TEST(testDecodeUTF8_2); LOGUNIT_TEST(testDecodeUTF8_3); @@ -106,6 +115,16 @@ LOGUNIT_CLASS(TranscoderTestCase) } #endif +#if LOG4CXX_CFSTRING_API + void decode5() + { + LogString nothing; + LogString decoded(LOG4CXX_STR("foo\n")); + Transcoder::decode(nothing, decoded); + LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("foo\n"), decoded); + } +#endif + enum { BUFSIZE = 255 }; @@ -169,7 +188,7 @@ LOGUNIT_CLASS(TranscoderTestCase) { // Test invalid multibyte string LogString greeting; - greeting.push_back( 0xff ); + greeting.push_back( logchar(0xff) ); std::wstring encoded; Transcoder::encode(greeting, encoded); @@ -247,6 +266,17 @@ LOGUNIT_CLASS(TranscoderTestCase) Transcoder::encode(decoded, encoded); } +#if LOG4CXX_CFSTRING_API + void encode7() + { + const LogString greeting(LOG4CXX_STR("Hello, World")); + CFStringRef encoded = Transcoder::encode(greeting); + LogString decoded; + Transcoder::decode(encoded, decoded); + LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("Hello, World"), decoded); + } +#endif + void testDecodeUTF8_1() { std::string src("a"); @@ -257,7 +287,7 @@ LOGUNIT_CLASS(TranscoderTestCase) void testDecodeUTF8_2() { - std::string src(1, 0x80); + std::string src(1, char(0x80)); LogString out; Transcoder::decodeUTF8(src, out); LOGUNIT_ASSERT_EQUAL(LogString(1, Transcoder::LOSSCHAR), out);