diff --git a/.gitignore b/.gitignore index 68bd9bb..f4770d7 100644 --- a/.gitignore +++ b/.gitignore @@ -105,4 +105,7 @@ docker-compose.override.yml *word-case-api.sln *DotNetAPI.Tests.csproj.lscache -*DotNetAPI.csproj.lscache \ No newline at end of file +*DotNetAPI.csproj.lscache + +*KT_Cache/ + diff --git a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt index b22b4ed..8beebc5 100644 --- a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt +++ b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt @@ -4,8 +4,25 @@ if(POLICY CMP0135) cmake_policy(SET CMP0135 NEW) endif() -# Add this near the top, after project() -if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR NOT CMAKE_BUILD_TYPE) +# 1. Initialize the project profile first so system variables exist +project(StringConversion) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +enable_testing() + +# 2. Apply explicit static linking constraints globally for cross-compilation +if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + # Force underlying components to compile with matching runtime definitions + set(gtest_force_shared_crt OFF CACHE BOOL "" FORCE) +else() + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +endif() + +# 3. Restrict AddressSanitizer strictly to native explicit Debug builds +if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") message(STATUS "Enabling AddressSanitizer for Debug build") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g") @@ -14,17 +31,10 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR NOT CMAKE_BUILD_TYPE) endif() endif() -project(StringConversion) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -enable_testing() - # --------------------------- # Global Settings # --------------------------- include_directories(include) -# Required for linking static code into a shared library on some platforms set(CMAKE_POSITION_INDEPENDENT_CODE ON) # --------------------------- @@ -54,20 +64,14 @@ target_include_directories(StringConversionLib PUBLIC include) # --------------------------- # 2. The Bridge DLL: ProcessStringDLL (SHARED) # --------------------------- -# This creates the actual file (libProcessStringDLL.dylib / .so) for .NET add_library(ProcessStringDLL SHARED src/ProcessStringDLL.cpp) - -# This tells the compiler "We are BUILDING the DLL, not using it" target_compile_definitions(ProcessStringDLL PRIVATE PROCESSSTRING_EXPORTS) -# This silences the 'strcpy' warning (C4996) seen in your logs if(WIN32) target_compile_definitions(ProcessStringDLL PRIVATE _CRT_SECURE_NO_WARNINGS) endif() target_link_libraries(ProcessStringDLL PRIVATE StringConversionLib) - -# Ensure the "lib" prefix is consistent for your scripts set_target_properties(ProcessStringDLL PROPERTIES PREFIX "lib") # --------------------------- @@ -80,8 +84,6 @@ target_link_libraries(app StringConversionLib) # 4. GoogleTest Setup # --------------------------- include(FetchContent) -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/main.zip @@ -97,4 +99,30 @@ add_executable(runTests ) target_link_libraries(runTests StringConversionLib gtest gtest_main) -add_test(NAME AllTests COMMAND runTests) \ No newline at end of file +# Force the test runner to link dependencies statically under MinGW +if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_options(runTests PRIVATE "-static" "-static-libgcc" "-static-libstdc++") +endif() + +add_test(NAME AllTests COMMAND runTests) + +# --------------------------- +# 6. Code Formatting (Clang-Format Automation) +# --------------------------- +find_program(CLANG_FORMAT_EXE + NAMES clang-format + HINTS /opt/homebrew/bin /usr/local/bin +) + +if(CLANG_FORMAT_EXE) + message(STATUS "Found clang-format: ${CLANG_FORMAT_EXE}") + file(GLOB_RECURSE ALL_FORMAT_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp" + "${PROJECT_SOURCE_DIR}/../Tests/CppTests/*.cpp" + ) + add_custom_target(format + COMMAND ${CLANG_FORMAT_EXE} -i -style=LLVM ${ALL_FORMAT_FILES} + COMMENT "Auto-formatting all C++ engine source..." + ) +endif() \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt b/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt index b7a1450..d4c5428 100644 --- a/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt +++ b/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt @@ -77,4 +77,27 @@ target_link_libraries(runTests StringConversionLib gtest gtest_main) # --------------------------- add_test(NAME AllTests COMMAND runTests) +# =================================================================== +# 6. Code Formatting (Clang-Format Automation) +# =================================================================== +find_program(CLANG_FORMAT_EXE + NAMES clang-format + HINTS /opt/homebrew/bin /usr/local/bin +) +if(CLANG_FORMAT_EXE) + message(STATUS "Found clang-format: ${CLANG_FORMAT_EXE}") + + file(GLOB_RECURSE ALL_FORMAT_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp" + "${PROJECT_SOURCE_DIR}/../Tests/CppTests/*.cpp" + ) + + add_custom_target(format + COMMAND ${CLANG_FORMAT_EXE} -i -style=LLVM ${ALL_FORMAT_FILES} + COMMENT "Auto-formatting C++ engine, application, and test suites..." + ) +else() + message(WARNING "clang-format executable not found. 'format' target will not be available.") +endif() \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile b/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile index bc4e094..7c3ac53 100644 --- a/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile +++ b/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile @@ -16,19 +16,24 @@ # * Artifact Extraction: Exposes the build directory for host-side consumption. # ----------------------------------------------------------------------------- -# --- STAGE 1: Build Environment (Native Toolchains Only) --- -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +ARG TARGET_PLATFORM=linux/amd64 +FROM --platform=${TARGET_PLATFORM} mcr.microsoft.com/dotnet/sdk:8.0 AS build-env -# Install C++ Native Toolchains (GCC for Linux, MinGW for Windows) -RUN apt-get update && apt-get install -y \ +# Install C++ Native Toolchains, Wine, and Xvfb for testing +RUN dpkg --add-architecture i386 && \ + apt-get update && apt-get install -y \ build-essential \ cmake \ mingw-w64 \ + wine \ + wine32 \ + wine64 \ + xvfb \ && rm -rf /var/lib/apt/lists/* WORKDIR /src -# Copy the entire repo context to preserve script and source paths +# Copy the entire repo context COPY . . # Ensure orchestrator script is executable @@ -40,14 +45,38 @@ RUN ./Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh ubuntu-late # --- STEP 2: Build Windows Artifacts (.dll via MinGW) --- RUN ./Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh windows-latest +# --- STEP 3: Verification Layer (Internal Tests) --- +WORKDIR /src/Backend/CaseConversionAPI/CppLib/build/windows-latest + +ENV WINEPREFIX=/root/.wine +ENV WINEARCH=win64 +ENV WINEDEBUG=-all +ENV WINEDLLOVERRIDES="mscoree,mshtml=" + +# Run Windows test suite via Wine +# Using absolute path to /usr/bin/xvfb-run ensures command execution +RUN echo "===== Running Windows GoogleTests via Wine =====" && \ + /usr/bin/xvfb-run --server-args="-screen 0 1024x768x24" \ + /usr/lib/wine/wine64 ./runTests.exe --gtest_color=yes 2>&1 | tee gtest_internal.log && \ + echo "===== Windows GoogleTests Passed =====" \ + || { \ + echo "=== WINDOWS GOOGLETEST CRASH LOG ==="; \ + cat gtest_internal.log; \ + exit 1; \ + } + +# Reset context for artifact extraction +WORKDIR /src + # ----------------------------------------------------------------------------- # STAGE 2: Export Layer (Minimal Delivery Vessel) # ----------------------------------------------------------------------------- -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +# Re-import target architecture variable for the final runtime stage context +ARG TARGET_PLATFORM=linux/amd64 +FROM --platform=${TARGET_PLATFORM} mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime WORKDIR /app # Export the raw C++ build artifacts for the host to extract via 'docker cp' -# This bypasses managed code publish to focus on native binary delivery. COPY --from=build-env /src/Backend/CaseConversionAPI/CppLib/build /src/Backend/CaseConversionAPI/CppLib/build # Note: No ENTRYPOINT defined as this container is utilized as an artifact source. \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh index 05b7f78..ef7714c 100755 --- a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh +++ b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh @@ -4,8 +4,10 @@ # Version : 1.0 */ # */ # Purpose : Coordinates Local (macOS) and Dockerized (Linux/Win) */ -# builds to generate a unified multi-platform binary set.*/ -# Location : backend/CaseConversionAPI/CppLib/Scripts/master-build.sh*/ +# builds to generate a unified multi-platform binary */ +# set. */ +# Location : Backend/CaseConversionAPI/CppLib/Scripts/ */ +# orchestrate-native-docker.sh */ # */ # Revision History: */ # ------------------------------------------------------------------ */ @@ -13,6 +15,10 @@ # ------------------------------------------------------------------ */ # 1.0 2026-05-14 Nitish Singh Initial Master Orchestrator*/ # with Docker extraction. */ +# 1.1 2026-05-16 Nitish Singh Added changed backend root */ +# path handling. */ +# 1.2 2026-05-20 Nitish Singh Aded google test execution */ +# inside the docker container*/ #*********************************************************************/ set -euo pipefail @@ -25,7 +31,7 @@ REPO_ROOT=$(realpath "$BACKEND_ROOT/..") # Configuration DOCKERFILE_PATH="$BACKEND_ROOT/CaseConversionAPI/CppLib/Scripts/Dockerfile" DIST_DIR="$BACKEND_ROOT/CaseConversionAPI/CppLib/build" -NATIVE_SCRIPT_REL="backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh" +NATIVE_SCRIPT_REL="Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh" log_info() { echo -e "\033[0;34m[$(date +'%T')] [INFO]\033[0m $1"; } log_success() { echo -e "\033[0;32m[$(date +'%T')] [SUCCESS]\033[0m $1"; } @@ -38,7 +44,6 @@ cd "$REPO_ROOT" if [[ "$(uname)" == "Darwin" ]]; then log_info "MacOS detected. Running local native build & tests..." - # Execute native script with the macos-latest target if bash "$NATIVE_SCRIPT_REL" macos-latest; then log_success "MacOS Local Build & Testing Complete." else @@ -52,41 +57,49 @@ fi # --- STEP 2: DOCKER CROSS-BUILD (LINUX & WINDOWS) --- log_info "Initiating Docker Build for Linux (.so) and Windows (.dll)..." -# Build the native-only Docker image -if docker build -t cpp-native-cross -f "$DOCKERFILE_PATH" .; then +if docker build \ + --progress=plain \ + --platform linux/amd64 \ + -t cpp-native-cross \ + -f "$DOCKERFILE_PATH" .; then + + # 1. Run Linux Tests + log_info "Running C++ Core GoogleTest suite inside Linux Container Environment..." + if docker run --rm cpp-native-cross /src/Backend/CaseConversionAPI/CppLib/build/ubuntu-latest/runTests; then + log_success "Linux (Ubuntu) Container Core Tests Passed Successfully." + else + log_error "Linux Core Tests Failed within the container context." + exit 1 + fi + + # 3. Extract and Sync Artifacts log_info "Extracting virtual artifacts from Docker..." - CONTAINER_ID=$(docker create cpp-native-cross) TEMP_EXTRACT="$DIST_DIR/docker_temp" mkdir -p "$TEMP_EXTRACT" - - # Copy the internal build directory to local temp - # The dot at the end ensures we copy contents of 'build' - docker cp "$CONTAINER_ID:/src/backend/CaseConversionAPI/CppLib/build/." "$TEMP_EXTRACT/" - - # Cleanup Docker immediately + + docker cp "$CONTAINER_ID:/src/Backend/CaseConversionAPI/CppLib/build/." "$TEMP_EXTRACT/" docker rm "$CONTAINER_ID" - docker rmi cpp-native-cross - # --- STEP 3: SYNC VIRTUAL ARTIFACTS --- log_info "Syncing cross-platform target folders..." - - # Target: ubuntu-latest + + # Sync Linux if [ -d "$TEMP_EXTRACT/ubuntu-latest" ]; then mkdir -p "$DIST_DIR/ubuntu-latest" cp "$TEMP_EXTRACT/ubuntu-latest/libProcessStringDLL.so" "$DIST_DIR/ubuntu-latest/" log_success "Artifact Secured: ubuntu-latest/libProcessStringDLL.so" fi - # Target: windows-latest + # Sync Windows if [ -d "$TEMP_EXTRACT/windows-latest" ]; then mkdir -p "$DIST_DIR/windows-latest" cp "$TEMP_EXTRACT/windows-latest/libProcessStringDLL.dll" "$DIST_DIR/windows-latest/" log_success "Artifact Secured: windows-latest/libProcessStringDLL.dll" fi - # Final Cleanup + # 4. Final Cleanup rm -rf "$TEMP_EXTRACT" + docker rmi cpp-native-cross else log_error "Docker build failed. Check Dockerfile and native toolchains." exit 1 diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh index 3381bb5..02d6996 100755 --- a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh +++ b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh @@ -19,6 +19,8 @@ # 1.5 2026-05-16 Nitish Singh Standardized logging, */ # execution context validation*/ # and dynamic path handling. */ +# 1.6 2026-05-28 Nitish Singh Injected pre-build format */ +# automation with set +e. */ #*********************************************************************/ set -euo pipefail @@ -124,6 +126,17 @@ fi # Modern CMake build cmake -S "$CPP_ROOT" -B "$BUILD_DIR" "${CMAKE_ARGS[@]}" +# Temporarily drop strict exit tracking to execute target code formatting safely +set +e +log_info "Executing shared framework auto-formatting via clang-format..." +cmake --build "$BUILD_DIR" --target format +if [ $? -eq 0 ]; then + log_success "Workspace formatting complete." +else + log_warn "Formatting target encountered an initialization anomaly or was skipped; proceeding." +fi +set -e # Re-engage strict execution tracking for compilation safety + log_info "Utilizing $NUM_CORES cores for parallel build..." cmake --build "$BUILD_DIR" --config Release --parallel "$NUM_CORES" diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh b/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh index 74ef91b..bcfce1f 100755 --- a/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh +++ b/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh @@ -11,12 +11,14 @@ # ------------------------------------------------------------------ */ # Version Date Author Description */ # ------------------------------------------------------------------ */ -# 1.0 2026-04-16 Nitish Singh Initial Swap Logic Script */ -# 1.1 2026-04-16 Nitish Singh Added Absolute Path Trap */ -# 1.2 2026-05-09 Nitish Singh Optimized for M2 P-Cores */ -# and enhanced error cleanup. * -# 1.3 2026-05-16 Nitish Singh Added execution context */ -# validation and dynamic path */ +# 1.0 2026-04-16 Nitish Singh Initial Swap Logic Script */ +# 1.1 2026-04-16 Nitish Singh Added Absolute Path Trap */ +# 1.2 2026-05-09 Nitish Singh Optimized for M2 P-Cores */ +# and enhanced error cleanup. */ +# 1.3 2026-05-16 Nitish Singh Added execution context */ +# validation and dynamic path */ +# 1.4 2026-05-28 Nitish Singh Automated clang-format via */ +# set +e error isolation. */ #*********************************************************************/ set -euo pipefail @@ -94,6 +96,17 @@ cmake -S "$CPP_ROOT" -B "$BUILD_DIR" \ -DUSE_PCORES=ON \ -DCMAKE_OSX_ARCHITECTURES=arm64 +# Temporarily disable strict exit-on-error for the formatter target +set +e +log_info "Executing source workspace auto-formatting via clang-format..." +cmake --build "$BUILD_DIR" --target format +if [ $? -eq 0 ]; then + log_success "Workspace formatting complete." +else + log_warn "Formatting target encountered an initialization anomaly; proceeding to compilation." +fi +set -e # Re-enable strict error tracking for compilation safety + log_info "Utilizing $NUM_CORES cores for parallel compilation..." cmake --build "$BUILD_DIR" --config Release --parallel "$NUM_CORES" diff --git a/Backend/CaseConversionAPI/CppLib/include/Client.hpp b/Backend/CaseConversionAPI/CppLib/include/Client.hpp index d2c80fe..16b60ae 100644 --- a/Backend/CaseConversionAPI/CppLib/include/Client.hpp +++ b/Backend/CaseConversionAPI/CppLib/include/Client.hpp @@ -72,7 +72,7 @@ class Client { */ ConversionResult execute(const std::string &input) const; - void setTraceId(const std::string& traceId); + void setTraceId(const std::string &traceId); }; #endif // CLIENT_HPP \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp b/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp index 470b953..de4a58d 100644 --- a/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp +++ b/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp @@ -55,60 +55,60 @@ */ class ConversionResult { private: - /// Pointer to heap-allocated C-style string - char* data; + /// Pointer to heap-allocated C-style string + char *data; public: - /** - * @brief Constructs a ConversionResult from input string. - * @param input Null-terminated C-string to copy. - */ - explicit ConversionResult(const char* input); + /** + * @brief Constructs a ConversionResult from input string. + * @param input Null-terminated C-string to copy. + */ + explicit ConversionResult(const char *input); - /** - * @brief Destructor releases allocated memory. - */ - ~ConversionResult(); + /** + * @brief Destructor releases allocated memory. + */ + ~ConversionResult(); - /*****************************************************************/ - /* Rule of 5: Copy Semantics */ - /*****************************************************************/ + /*****************************************************************/ + /* Rule of 5: Copy Semantics */ + /*****************************************************************/ - /** - * @brief Copy constructor (deep copy). - * @param other Source object to copy from. - */ - ConversionResult(const ConversionResult& other); + /** + * @brief Copy constructor (deep copy). + * @param other Source object to copy from. + */ + ConversionResult(const ConversionResult &other); - /** - * @brief Copy assignment operator (deep copy). - * @param other Source object to assign from. - * @return Reference to current object. - */ - ConversionResult& operator=(const ConversionResult& other); + /** + * @brief Copy assignment operator (deep copy). + * @param other Source object to assign from. + * @return Reference to current object. + */ + ConversionResult &operator=(const ConversionResult &other); - /*****************************************************************/ - /* Rule of 5: Move Semantics (Performance Optimization) */ - /*****************************************************************/ + /*****************************************************************/ + /* Rule of 5: Move Semantics (Performance Optimization) */ + /*****************************************************************/ - /** - * @brief Move constructor (transfers ownership). - * @param other Source object to move from. - */ - ConversionResult(ConversionResult&& other) noexcept; + /** + * @brief Move constructor (transfers ownership). + * @param other Source object to move from. + */ + ConversionResult(ConversionResult &&other) noexcept; - /** - * @brief Move assignment operator (transfers ownership). - * @param other Source object to move from. - * @return Reference to current object. - */ - ConversionResult& operator=(ConversionResult&& other) noexcept; + /** + * @brief Move assignment operator (transfers ownership). + * @param other Source object to move from. + * @return Reference to current object. + */ + ConversionResult &operator=(ConversionResult &&other) noexcept; - /** - * @brief Returns the underlying C-style string. - * @return Pointer to null-terminated string. - */ - [[nodiscard]] const char* get_c_str() const; + /** + * @brief Returns the underlying C-style string. + * @return Pointer to null-terminated string. + */ + [[nodiscard]] const char *get_c_str() const; }; #endif // CONVERSION_RESULT_HPP \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp b/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp index 87cad93..0d0e4c1 100644 --- a/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp +++ b/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp @@ -35,8 +35,8 @@ #define PROCESSSTRINGDLL_HPP /*********************************************************************/ -/* Platform-Specific API Macros */ -/* */ +/* Platform-Specific API Macros */ +/* */ /* Configures symbol visibility for the dynamic linker. */ /* - Windows: Uses __declspec to manage DLL export/import tables. */ /* - macOS/Linux: Uses visibility attributes to ensure P/Invoke */ @@ -68,7 +68,8 @@ extern "C" { * @return C-string result (valid until next call). Caller must free using * freeString. */ -API const char *processStringDLL(const char *input, int len, int choice, const char *traceId); +API const char *processStringDLL(const char *input, int len, int choice, + const char *traceId); /** * @brief Frees memory allocated by processStringDLL diff --git a/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp b/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp index 6814aba..9a084f0 100644 --- a/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp +++ b/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp @@ -104,7 +104,8 @@ #include "StringConversionFactory.hpp" extern "C" { -char *processStringDLL(const char *input, int len, int choice, const char *traceId); +char *processStringDLL(const char *input, int len, int choice, + const char *traceId); void freeString(char *str); } @@ -254,9 +255,9 @@ TEST(ProcessStringDLL, MultipleCalls) { // 5. MEMORY MANAGEMENT TESTS FOR DLL // ============================================================ -TEST(ProcessStringDLL, MemoryNotNull) { - const char *result = processStringDLL("hello", 4, 4, "test-trace-id"); +TEST(ProcessStringDLL, MemoryNotNull) { + const char *result = processStringDLL("hello", 4, 4, "test-trace-id"); ASSERT_NE(result, nullptr); // Cast to char* if your freeString expects it, or keep it consistent - freeString(const_cast(result)); + freeString(const_cast(result)); } \ No newline at end of file diff --git a/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp b/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp index 843117a..3adb15a 100644 --- a/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp +++ b/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp @@ -132,7 +132,8 @@ TEST(ProcessStringTest, ProcessStringAlternating) { std::string input = "Hello World!"; int choice = 1; // Alternating case - std::string output = ConversionResult(processString(input, choice)).get_c_str(); + std::string output = + ConversionResult(processString(input, choice)).get_c_str(); logConversion("ProcessString Alternating", input, output); @@ -143,7 +144,8 @@ TEST(ProcessStringTest, ProcessStringReverse) { std::string input = "Hello World!"; int choice = 7; // Reverse - std::string output = ConversionResult(processString(input, choice)).get_c_str(); + std::string output = + ConversionResult(processString(input, choice)).get_c_str(); logConversion("ProcessString Reverse", input, output); @@ -175,8 +177,8 @@ TEST(UpperCasePerformanceTest, LargeInput) { std::string largeInput(1'000'000, 'a'); auto start = std::chrono::high_resolution_clock::now(); - auto resultObj = converter.convert(largeInput); - const char* resultStr = resultObj.get_c_str(); + auto resultObj = converter.convert(largeInput); + const char *resultStr = resultObj.get_c_str(); auto end = std::chrono::high_resolution_clock::now(); auto duration = diff --git a/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp b/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp index 51120ab..e945757 100644 --- a/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp +++ b/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp @@ -33,11 +33,11 @@ // Core Interfaces #include "Client.hpp" +#include "ConversionResult.hpp" #include "IStringConversion.hpp" #include "ProcessString.hpp" #include "StringConversionFactory.hpp" #include "TestHelpers.hpp" -#include "ConversionResult.hpp" // Basic Conversions #include "AlternatingCaseConversion.hpp" @@ -114,12 +114,14 @@ TEST(InvertWordsConversionTest, Basic) { TEST(KebabCaseConversionTest, Basic) { KebabCaseConversion conv; - EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), "hello-world-example"); + EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), + "hello-world-example"); } TEST(SnakeCaseConversionTest, Basic) { SnakeCaseConversion conv; - EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), "hello_world_example"); + EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), + "hello_world_example"); } TEST(RemoveSpacesConversionTest, Basic) { @@ -136,7 +138,7 @@ TEST(LeetSpeakConversionTest, Basic) { LeetSpeakConversion conv; EXPECT_STREQ(conv.convert("Hello").get_c_str(), "H3ll0"); EXPECT_STREQ(conv.convert("Testing").get_c_str(), - "73571ng"); // ensure mapping matches implementation + "73571ng"); // ensure mapping matches implementation } // @@ -237,47 +239,63 @@ TEST(ClientTest, NoStrategySet) { TEST(ProcessStringTest, BasicFlow) { EXPECT_STREQ(processString("hello world", - static_cast(ConversionChoice::Alternating)).get_c_str(), - "HeLlO WoRlD"); + static_cast(ConversionChoice::Alternating)) + .get_c_str(), + "HeLlO WoRlD"); EXPECT_STREQ(processString("hello world", - static_cast(ConversionChoice::Capitalize)).get_c_str(), - "Hello World"); - EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Lower)).get_c_str(), - "hello"); - EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Upper)).get_c_str(), - "HELLO"); - EXPECT_STREQ(processString("hELLO wORLD", - static_cast(ConversionChoice::Sentence)).get_c_str(), - "Hello world"); - EXPECT_STREQ(processString("HeLLo", static_cast(ConversionChoice::Toggle)).get_c_str(), - "hEllO"); - EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Reverse)).get_c_str(), - "olleH"); + static_cast(ConversionChoice::Capitalize)) + .get_c_str(), + "Hello World"); + EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Lower)) + .get_c_str(), + "hello"); + EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Upper)) + .get_c_str(), + "HELLO"); + EXPECT_STREQ( + processString("hELLO wORLD", static_cast(ConversionChoice::Sentence)) + .get_c_str(), + "Hello world"); + EXPECT_STREQ( + processString("HeLLo", static_cast(ConversionChoice::Toggle)) + .get_c_str(), + "hEllO"); + EXPECT_STREQ( + processString("Hello", static_cast(ConversionChoice::Reverse)) + .get_c_str(), + "olleH"); } TEST(ProcessStringTest, AdvancedChoices) { EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::RemoveVowels)).get_c_str(), - "Hll Wrld"); + static_cast(ConversionChoice::RemoveVowels)) + .get_c_str(), + "Hll Wrld"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::RemoveSpaces)).get_c_str(), - "HelloWorld"); + static_cast(ConversionChoice::RemoveSpaces)) + .get_c_str(), + "HelloWorld"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::InvertWords)).get_c_str(), - "olleH dlroW"); + static_cast(ConversionChoice::InvertWords)) + .get_c_str(), + "olleH dlroW"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::SnakeCase)).get_c_str(), - "hello_world"); + static_cast(ConversionChoice::SnakeCase)) + .get_c_str(), + "hello_world"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::KebabCase)).get_c_str(), - "hello-world"); + static_cast(ConversionChoice::KebabCase)) + .get_c_str(), + "hello-world"); EXPECT_STREQ( - processString("Test", static_cast(ConversionChoice::LeetSpeak)).get_c_str(), + processString("Test", static_cast(ConversionChoice::LeetSpeak)) + .get_c_str(), "7357"); } TEST(ProcessStringTest, InvalidChoice) { - EXPECT_STREQ(processString("Hello", 99).get_c_str(), "hello"); // invalid choice falls back + EXPECT_STREQ(processString("Hello", 99).get_c_str(), + "hello"); // invalid choice falls back } //