[mapguide-commits] r10238 - in branches/4.0/MgDev: Bindings/src/Test/Java Bindings/src/Test/Java/extlib Bindings/src/Test/Java/src/org/osgeo/mapguide/test/common Bindings/src/Test/Php Oem/DWFTK/develop/global/src/dwfcore Web/src Web/src/HttpHandler Web/src/WebTestRunner

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Mon Nov 2 06:30:20 PST 2026


Author: jng
Date: 2026-11-02 06:30:19 -0800 (Mon, 02 Nov 2026)
New Revision: 10238

Added:
   branches/4.0/MgDev/Bindings/src/Test/Java/extlib/libsqlite4java-linux-amd64.so
   branches/4.0/MgDev/Web/src/WebTestRunner/CMakeLists.txt
Modified:
   branches/4.0/MgDev/Bindings/src/Test/Java/README.txt
   branches/4.0/MgDev/Bindings/src/Test/Java/src/org/osgeo/mapguide/test/common/CommonUtility.java
   branches/4.0/MgDev/Bindings/src/Test/Php/TestContext.php
   branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.cpp
   branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.h
   branches/4.0/MgDev/Web/src/CMakeLists.txt
   branches/4.0/MgDev/Web/src/HttpHandler/OgcServer.cpp
Log:
#2493: Various fixes to support web tier test suite execution on Linux

Modified: branches/4.0/MgDev/Bindings/src/Test/Java/README.txt
===================================================================
--- branches/4.0/MgDev/Bindings/src/Test/Java/README.txt	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Bindings/src/Test/Java/README.txt	2026-11-02 14:30:19 UTC (rev 10238)
@@ -20,4 +20,25 @@
 
 Unit tests results will be logged to unittest.log
 
-The default ant build.xml properties is configured for 64-bit release configuration of MapGuide. Where applicable, you should override these properties to match your specific build configuration.
\ No newline at end of file
+The default ant build.xml properties is configured for 64-bit release configuration of MapGuide. Where applicable, you should override these properties to match your specific build configuration.
+
+Running the tests on Linux
+==========================
+
+The suites read their .dump fixtures through sqlite4java, which needs a native library
+for the platform it runs on. The Windows ones are checked in under extlib/; the Linux one
+is libsqlite4java-linux-amd64.so, in the same directory, so the ant `dist` target copies it
+next to MgUnitTest.jar and it only has to be on java.library.path:
+
+    java -Djava.library.path=<dist>:<mapguide install>/webserverextensions/lib64 \
+         -jar MgUnitTest.jar <webconfig.ini> <log file>
+
+libsqlite4java-linux-amd64.so is the official 1.0.392 artifact for x86-64, taken from
+Maven Central (com.almworks.sqlite4java:libsqlite4java-linux-amd64:1.0.392, packaging
+"so"); its sha1 (5a97aa1b643252eb9be0901037cb440c2e145956) matches the one Maven Central
+publishes. SVN's default global-ignores matches *.so, so it has to be added with
+`svn add --force`.
+
+run_mapguide_tests.sh --tier web --web-suite java does all of this: it builds the runner
+with ant into a staged test pack, starts and stops the server, and reports the
+"Tests failed/run" summary.

Added: branches/4.0/MgDev/Bindings/src/Test/Java/extlib/libsqlite4java-linux-amd64.so
===================================================================
(Binary files differ)

Index: branches/4.0/MgDev/Bindings/src/Test/Java/extlib/libsqlite4java-linux-amd64.so
===================================================================
--- branches/4.0/MgDev/Bindings/src/Test/Java/extlib/libsqlite4java-linux-amd64.so	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Bindings/src/Test/Java/extlib/libsqlite4java-linux-amd64.so	2026-11-02 14:30:19 UTC (rev 10238)

Property changes on: branches/4.0/MgDev/Bindings/src/Test/Java/extlib/libsqlite4java-linux-amd64.so
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/x-sharedlib
\ No newline at end of property
Modified: branches/4.0/MgDev/Bindings/src/Test/Java/src/org/osgeo/mapguide/test/common/CommonUtility.java
===================================================================
--- branches/4.0/MgDev/Bindings/src/Test/Java/src/org/osgeo/mapguide/test/common/CommonUtility.java	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Bindings/src/Test/Java/src/org/osgeo/mapguide/test/common/CommonUtility.java	2026-11-02 14:30:19 UTC (rev 10238)
@@ -701,7 +701,11 @@
                         Console.WriteLine("Read path from current directory");
 
                     //System.out.println("Param (" + paramName+ "): " + str);
-                    String relPath = str.replaceAll("../../TestData", "").replaceAll("..\\\\..\\\\TestData", "");
+                    // The dumps were recorded on Windows, so the relative path under TestData can
+                    // use either separator. Normalising before stripping the prefix is not
+                    // optional: the remainder below the prefix keeps its separators, and a
+                    // backslash is not one on Linux.
+                    String relPath = str.replace('\\', '/').replace("../../TestData", "");
                     String resolved = TestEnvConfiguration.resolveTestDataPath(relPath, true);
                     //System.out.println("Resolves to: " + resolved);
                     if (resolved != null)

Modified: branches/4.0/MgDev/Bindings/src/Test/Php/TestContext.php
===================================================================
--- branches/4.0/MgDev/Bindings/src/Test/Php/TestContext.php	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Bindings/src/Test/Php/TestContext.php	2026-11-02 14:30:19 UTC (rev 10238)
@@ -51,8 +51,12 @@
         if (strlen($relPath) === 0) {
             return Utils::GetPath($relPath);
         }
+        // The dumps were recorded on Windows, so the relative path under TestData can use
+        // either separator. Normalising before stripping the prefix is not optional: the
+        // remainder below the prefix keeps its separators, and a backslash is not one on
+        // Linux.
+        $relPath = str_replace("\\", "/", $relPath);
         $relPathFixed = str_replace("../../TestData", $this->testDataRootPath, $relPath);
-        $relPathFixed = str_replace("..\\..\\TestData", $this->testDataRootPath, $relPathFixed);
         return $relPathFixed;
     }
     public function getDataFilePath($relPath, $throwIfNotFound = true) {

Modified: branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.cpp
===================================================================
--- branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.cpp	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.cpp	2026-11-02 14:30:19 UTC (rev 10238)
@@ -24,8 +24,46 @@
 #include "dwfcore/Exception.h"
 using namespace DWFCore;
 
+// The message buffer is _zMessage[512]; one element is the terminator. Kept unsigned so the
+// bounded scan below compares like with like: MSVC builds this file at /W4, and the VC 8.0
+// project turns warnings into errors.
+#define _DWFCORE_EXCEPTION_MESSAGE_MAX_WCHARS 511u
 
 
+// Copy a message into the fixed buffer, always leaving a complete terminating null behind.
+//
+// The buffer holds 512 wide characters, so at most 511 are copied and _zMessage[511] is reserved
+// for the terminator. Zeroing "nBytes + 2" after the copy, which this used to do, does not
+// terminate the string: nBytes is always a multiple of sizeof(wchar_t), so the two zeroed bytes
+// land in the low half of the first wchar_t past the copy and the uninitialised high half makes
+// it non-zero. Every wcslen() on the message then runs off the end of the exception object - and
+// the first one to do so is the copy constructor below, reached by `throw e;` on a caught
+// exception (AddressSanitizer: heap-buffer-overflow in __interceptor_wcslen).
+//
+// The scan is bounded by the buffer's capacity rather than by wcslen(), so it cannot over-read
+// the source either: the source of a copy is another exception's buffer, which is the one this
+// code has to be able to trust.
+static void
+dwfCopyExceptionMessage( wchar_t* pBuffer, const wchar_t* zMessage )
+{
+    size_t nChars = 0;
+
+    if (zMessage != NULL)
+    {
+        while (nChars < _DWFCORE_EXCEPTION_MESSAGE_MAX_WCHARS && zMessage[nChars] != 0)
+        {
+            ++nChars;
+        }
+
+        if (nChars > 0)
+        {
+            DWFCORE_COPY_MEMORY( pBuffer, zMessage, nChars * sizeof(wchar_t) );
+        }
+    }
+
+    pBuffer[nChars] = 0;
+}
+
 _DWFCORE_API
 DWFException::DWFException( const wchar_t* zMessage,
                             const char*    zFunction,
@@ -36,15 +74,7 @@
             , _zFile( zFile )
             , _nLine( nLine )
 {
-    _zMessage[0] = 0;
-
-    if (zMessage)
-    {
-        size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(zMessage) );
-
-        DWFCORE_ZERO_MEMORY( _zMessage, nBytes + 2 );
-        DWFCORE_COPY_MEMORY( _zMessage, zMessage, nBytes );
-    }
+    dwfCopyExceptionMessage( _zMessage, zMessage );
 }
 
 _DWFCORE_API
@@ -61,15 +91,7 @@
             , _zFile( rEx._zFile )
             , _nLine( rEx._nLine )
 {
-    _zMessage[0] = 0;
-
-    if (rEx._zMessage)
-    {
-        size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(rEx._zMessage) );
-
-        DWFCORE_ZERO_MEMORY( _zMessage, nBytes + 2 );
-        DWFCORE_COPY_MEMORY( _zMessage, rEx._zMessage, nBytes );
-    }
+    dwfCopyExceptionMessage( _zMessage, rEx._zMessage );
 }
 
 _DWFCORE_API
@@ -81,16 +103,8 @@
     _zFile = rEx._zFile;
     _nLine = rEx._nLine;
 
-    _zMessage[0] = 0;
+    dwfCopyExceptionMessage( _zMessage, rEx._zMessage );
 
-    if (rEx._zMessage)
-    {
-        size_t nBytes = min( 511*sizeof(wchar_t), DWFCORE_WIDE_STRING_LENGTH_IN_BYTES(rEx._zMessage) );
-
-        DWFCORE_ZERO_MEMORY( _zMessage, nBytes + 2 );
-        DWFCORE_COPY_MEMORY( _zMessage, rEx._zMessage, nBytes );
-    }
-
     return *this;
 }
 

Modified: branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.h
===================================================================
--- branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.h	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Oem/DWFTK/develop/global/src/dwfcore/Exception.h	2026-11-02 14:30:19 UTC (rev 10238)
@@ -140,7 +140,8 @@
     ///         Constructor
     ///
     ///\param   zMessage    Describes the exception event.
-    ///                     This string is copied into a local buffer and is limited to \b 512 wide characters.
+    ///                     This string is copied into a local buffer and is limited to \b 511 wide characters
+    ///                     plus a terminating null.
     ///\param   zFunction   The function in which the event occured.  The \b __func__ macro is recommended.
     ///\param   zFile       The file in which the event occured. The \b __FILE__ macro is recommended.
     ///\param   nLine       The line number in the file in which the event occured.  The \b __LINE__ macro is recommended.

Modified: branches/4.0/MgDev/Web/src/CMakeLists.txt
===================================================================
--- branches/4.0/MgDev/Web/src/CMakeLists.txt	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Web/src/CMakeLists.txt	2026-11-02 14:30:19 UTC (rev 10238)
@@ -7,6 +7,7 @@
 add_subdirectory(HttpHandler)
 
 if (NOT MG_COMMON_SUBSET_ONLY)
+    add_subdirectory(WebTestRunner)
     add_subdirectory(DevHttpServer)
     #add_subdirectory(CgiAgent)
 

Modified: branches/4.0/MgDev/Web/src/HttpHandler/OgcServer.cpp
===================================================================
--- branches/4.0/MgDev/Web/src/HttpHandler/OgcServer.cpp	2026-11-02 04:48:51 UTC (rev 10237)
+++ branches/4.0/MgDev/Web/src/HttpHandler/OgcServer.cpp	2026-11-02 14:30:19 UTC (rev 10238)
@@ -1612,8 +1612,10 @@
 
     // Kill the UNICODE Byte Order Mark, if there is one.
     if(pSlurp[0] == 0xfeff) {
-        memcpy(pSlurp,pSlurp+1,iSizeInBytes);
-        iSizeInBytes -= 2;
+        // The source and destination overlap by one CHARTYPE here, which memcpy does not allow;
+        // ASan stops the process on it (memcpy-param-overlap), which is how this was found.
+        memmove(pSlurp,pSlurp+1,iSizeInBytes);
+        iSizeInBytes -= sizeof(CHARTYPE);
     }
 
     // Make sure the thing is null-terminated.

Added: branches/4.0/MgDev/Web/src/WebTestRunner/CMakeLists.txt
===================================================================
--- branches/4.0/MgDev/Web/src/WebTestRunner/CMakeLists.txt	                        (rev 0)
+++ branches/4.0/MgDev/Web/src/WebTestRunner/CMakeLists.txt	2026-11-02 14:30:19 UTC (rev 10238)
@@ -0,0 +1,49 @@
+find_package (JsonCpp REQUIRED)
+
+include_directories(${MG_OEM_CATCH2_INCLUDE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${MG_WEB_DIR}/src/HttpHandler
+    ${MG_WEB_DIR}/src/WebSupport
+    ${MG_WEB_DIR}/src/WebApp
+    ${MG_COMMON_DIR}/MdfModel
+    ${MG_COMMON_DIR}/MdfParser
+    ${MG_COMMON_DIR}/Foundation
+    ${MG_COMMON_DIR}/Geometry
+    ${MG_COMMON_DIR}/PlatformBase
+    ${MG_COMMON_DIR}/MapGuideCommon
+    ${ACE_INCLUDE_DIR}
+    ${XERCESC_INCLUDE_DIR}
+    ${JsonCpp_INCLUDE_DIR}
+    ${FDO_INCLUDE_DIR}
+)
+
+set(MgWebTestRunner_SRCS
+    GeoJsonTest.cpp
+    main.cpp
+    OgcTest.cpp
+    TestListener.cpp
+    WebLayoutTest.cpp
+)
+
+add_executable(MgWebTestRunner ${MgWebTestRunner_SRCS})
+add_sanitizers(MgWebTestRunner)
+set_target_properties( MgWebTestRunner
+    PROPERTIES OUTPUT_NAME "MgWebTestRunner" )
+
+target_link_libraries(MgWebTestRunner
+    ${ACE_LIBRARY}
+    ${XERCESC_LIBRARIES}
+    ${JsonCpp_LIBRARY}
+    MgWebSupport${MG_VERSION_SUFFIX}
+    MgHttpHandler${MG_VERSION_SUFFIX}
+    MgWebApp${MG_VERSION_SUFFIX}
+    MgMapGuideCommon${MG_VERSION_SUFFIX}
+    MgMdfParser${MG_VERSION_SUFFIX}
+    MgMdfModel${MG_VERSION_SUFFIX}
+    MgPlatformBase${MG_VERSION_SUFFIX}
+    MgFoundation${MG_VERSION_SUFFIX}
+    MgGeometry${MG_VERSION_SUFFIX}
+)
+
+# The suite reads its fixtures from TestData relative to the working directory
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/TestData DESTINATION ${CMAKE_CURRENT_BINARY_DIR})



More information about the mapguide-commits mailing list