Commit 661826d46 for clamav.net

commit 661826d46890fde08651d5eab6fa4d6e17a8dd61
Author: Jonas Zaddach <5988756+zaddach@users.noreply.github.com>
Date:   Thu Aug 7 13:55:42 2025 +0200

    Tests: Fix Windows compatibility with testing example programs

    Don't concatenate pythonpath and str

    Fix test program path for Windows Ninja Multi-Config

    Use environment variable to pass cl_cvdunpack_test location to test

    Use ENABLE_EXAMPLES instead of ENABLE_TESTS to gate ex_cl_cvdunpack

    Directly use the target's path on Windows

    Also change the program finding for ex_scan_callbacks_test

    Fix python paths handling

    Fix the order of some expected results which were incorrect and for
    some reason only failed when tested on Windows.
    This final fix in this commit provided by Val Snyder.

diff --git a/examples/ex_scan_callbacks.c b/examples/ex_scan_callbacks.c
index df4b27957..3f606b3a0 100644
--- a/examples/ex_scan_callbacks.c
+++ b/examples/ex_scan_callbacks.c
@@ -375,8 +375,9 @@ script_context_t *read_script_commands(const char *script_filepath)
     }

     size_t bytes_read = fread(script_contents, 1, script_size, script_file);
-    if (bytes_read != (size_t)script_size) {
-        printf("Error reading script file %s\n", script_filepath);
+    if (bytes_read != (size_t)script_size && ferror(script_file) != 0) {
+        printf("Error reading script file %s. Bytes read: %zu, Script size: %zu\n",
+               script_filepath, bytes_read, (size_t)script_size);
         status = 2;
         goto done;
     }
diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt
index 87ecd1d9f..ed7437546 100644
--- a/unit_tests/CMakeLists.txt
+++ b/unit_tests/CMakeLists.txt
@@ -196,6 +196,10 @@ if(WIN32)
         file(TO_NATIVE_PATH $<TARGET_FILE_DIR:check_clamav>/freshclam.exe       FRESHCLAM)
         file(TO_NATIVE_PATH $<TARGET_FILE_DIR:check_clamav>/sigtool.exe         SIGTOOL)
     endif()
+    if(ENABLE_EXAMPLES)
+        file(TO_NATIVE_PATH $<TARGET_FILE_DIR:check_clamav>/ex_scan_callbacks.exe EX_SCAN_CALLBACKS)
+        file(TO_NATIVE_PATH $<TARGET_FILE_DIR:check_clamav>/ex_cl_cvdunpack.exe   EX_CL_CVDUNPACK)
+    endif()

     # Convert the CVD_CERTS_DIR to a native path for Windows (replacing forward slashes with backslashes).
     file(TO_NATIVE_PATH ${CVD_CERTS_DIR} CVD_CERTS_DIR)
@@ -259,6 +263,10 @@ else()
         if(ENABLE_CLAMONACC)
             set(CLAMONACC          $<TARGET_FILE:clamonacc>)
         endif()
+        if(ENABLE_EXAMPLES)
+            set(EX_SCAN_CALLBACKS  $<TARGET_FILE:ex_scan_callbacks>)
+            set(EX_CL_CVDUNPACK    $<TARGET_FILE:ex_cl_cvdunpack>)
+        endif()
     endif()
 endif()

@@ -302,6 +310,8 @@ set(ENVIRONMENT
     SIGTOOL=${SIGTOOL}
     CLAMAV_MILTER=${CLAMAV_MILTER}
     CLAMONACC=${CLAMONACC}
+    EX_SCAN_CALLBACKS=${EX_SCAN_CALLBACKS}
+    EX_CL_CVDUNPACK=${EX_CL_CVDUNPACK}
 )


@@ -314,6 +324,7 @@ if(NOT MSVC)
     list(APPEND ENVIRONMENT "OPENSSL_LIBS=${OPENSSL_LIBS}")
 endif()
 list(APPEND ENVIRONMENT "OPENSSL_LIB_DIR=${OPENSSL_LIB_DIR}")
+list(APPEND ENVIRONMENT "CONFIGURATION=$<CONFIG>")

 #
 # The Tests
@@ -495,6 +506,14 @@ if(WIN32)
                 file(COPY $<TARGET_FILE:clamconf> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
                 file(COPY $<TARGET_FILE:freshclam-bin> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
                 file(COPY $<TARGET_FILE:sigtool> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
+
+                # Collect example programs, if built with ENABLE_EXAMPLES=ON
+                if ($<TARGET_EXISTS:ex_scan_callbacks>)
+                    file(COPY $<TARGET_FILE:$<IF:$<TARGET_EXISTS:ex_scan_callbacks>,ex_scan_callbacks,check_clamav>> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
+                endif()
+                if ($<TARGET_EXISTS:ex_cl_cvdunpack>)
+                    file(COPY $<TARGET_FILE:$<IF:$<TARGET_EXISTS:ex_cl_cvdunpack>,ex_cl_cvdunpack,check_clamav>> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
+                endif()
             ]])
         else()
             # We don't have libfreshclam unit tests, so no need to check if ENABLE_LIBCLAMAV_ONLY is enabled.
@@ -538,6 +557,14 @@ if(WIN32)
                 if ($<TARGET_EXISTS:ClamAV::libunrar_iface>)
                     file(COPY $<TARGET_FILE:$<IF:$<TARGET_EXISTS:ClamAV::libunrar_iface>,ClamAV::libunrar_iface,check_clamav>> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
                 endif()
+
+                # Collect example programs, if built with ENABLE_EXAMPLES=ON
+                if ($<TARGET_EXISTS:ex_scan_callbacks>)
+                    file(COPY $<TARGET_FILE:$<IF:$<TARGET_EXISTS:ex_scan_callbacks>,ex_scan_callbacks,check_clamav>> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
+                endif()
+                if ($<TARGET_EXISTS:ex_cl_cvdunpack>)
+                    file(COPY $<TARGET_FILE:$<IF:$<TARGET_EXISTS:ex_cl_cvdunpack>,ex_cl_cvdunpack,check_clamav>> DESTINATION $<TARGET_FILE_DIR:check_clamav>)
+                endif()
             ]])
         endif()

diff --git a/unit_tests/examples/ex_cl_cvdunpack_test.py b/unit_tests/examples/ex_cl_cvdunpack_test.py
index cf23d61a2..cd6b2c4d1 100644
--- a/unit_tests/examples/ex_cl_cvdunpack_test.py
+++ b/unit_tests/examples/ex_cl_cvdunpack_test.py
@@ -8,6 +8,8 @@ import os
 import platform
 import shutil
 import sys
+from pathlib import Path
+

 sys.path.append('../unit_tests')
 import testcase
@@ -24,27 +26,9 @@ class TC(testcase.TestCase):
         super(TC, cls).setUpClass()

         # Find the example program
-        if operating_system == 'windows':
-            # Windows needs the example program to be in the same directory as libclamav and the rest.
-            shutil.copy(
-                str(TC.path_build / 'examples' / program_name + '.exe'),
-                str(TC.path_build / 'unit_tests' / program_name + '.exe'),
-            )
-
-            TC.example_program = TC.path_build / 'unit_tests' / program_name + '.exe'
-            if not TC.example_program.exists():
-                # Try the static version.
-                TC.example_program = TC.path_build / 'unit_tests' / program_name + '_static.exe'
-                if not TC.example_program.exists():
-                    raise Exception('Could not find the example program.')
-        else:
-            # Linux and macOS can use the LD_LIBRARY_PATH environment variable to find libclamav
-            TC.example_program = TC.path_build / 'examples' / program_name
-            if not TC.example_program.exists():
-                # Try the static version.
-                TC.example_program = TC.path_build / 'examples' / program_name + '_static'
-                if not TC.example_program.exists():
-                    raise Exception('Could not find the example program.')
+        TC.example_program = Path(os.getenv("EX_CL_CVDUNPACK"))
+        if not TC.example_program.exists():
+            raise Exception(f'Could not find the example program {TC.example_program}')

         # Copy the test cvd to the temp directory
         shutil.copyfile(
diff --git a/unit_tests/examples/ex_scan_callbacks_test.py b/unit_tests/examples/ex_scan_callbacks_test.py
index 03b69aab4..875d4dc2b 100644
--- a/unit_tests/examples/ex_scan_callbacks_test.py
+++ b/unit_tests/examples/ex_scan_callbacks_test.py
@@ -41,6 +41,7 @@ import os
 import platform
 import shutil
 import sys
+from pathlib import Path

 sys.path.append('../unit_tests')
 import testcase
@@ -58,27 +59,9 @@ class TC(testcase.TestCase):
         super(TC, cls).setUpClass()

         # Find the example program
-        if operating_system == 'windows':
-            # Windows needs the example program to be in the same directory as libclamav and the rest.
-            shutil.copy(
-                str(TC.path_build / 'examples' / program_name + '.exe'),
-                str(TC.path_build / 'unit_tests' / program_name + '.exe'),
-            )
-
-            TC.example_program = TC.path_build / 'unit_tests' / program_name + '.exe'
-            if not TC.example_program.exists():
-                # Try the static version.
-                TC.example_program = TC.path_build / 'unit_tests' / program_name + '_static.exe'
-                if not TC.example_program.exists():
-                    raise Exception('Could not find the example program.')
-        else:
-            # Linux and macOS can use the LD_LIBRARY_PATH environment variable to find libclamav
-            TC.example_program = TC.path_build / 'examples' / program_name
-            if not TC.example_program.exists():
-                # Try the static version.
-                TC.example_program = TC.path_build / 'examples' / program_name + '_static'
-                if not TC.example_program.exists():
-                    raise Exception('Could not find the example program.')
+        TC.example_program = Path(os.getenv("EX_SCAN_CALLBACKS"))
+        if not TC.example_program.exists():
+            raise Exception(f'Could not find the example program {TC.example_program}')

     @classmethod
     def tearDownClass(cls):
@@ -168,8 +151,8 @@ class TC(testcase.TestCase):
             f.write('2\n') # Return CL_SUCCESS to keep scanning

             expected_results += [
-                'Recursion Level:    0',
                 'In POST_SCAN callback',
+                'Recursion Level:    0',
                 'File Name:          clam.zip',
                 'File Type:          CL_TYPE_ZIP'
             ]
@@ -287,8 +270,8 @@ class TC(testcase.TestCase):
             f.write('2\n') # Return CL_SUCCESS to keep scanning

             expected_results += [
-                'Recursion Level:    0',
                 'In POST_SCAN callback',
+                'Recursion Level:    0',
                 'File Name:          clam.zip',
                 'File Type:          CL_TYPE_ZIP'
             ]
@@ -401,8 +384,8 @@ class TC(testcase.TestCase):
             f.write('2\n') # Return CL_SUCCESS to keep scanning

             expected_results += [
-                'Recursion Level:    0',
                 'In POST_SCAN callback',
+                'Recursion Level:    0',
                 'File Name:          clam.zip',
                 'File Type:          CL_TYPE_ZIP',
             ]
@@ -643,8 +626,8 @@ class TC(testcase.TestCase):
             f.write('3\n') # Return CL_VIRUS to keep scanning and accept the alert

             expected_results += [
-                'Recursion Level:    0',
                 'In POST_SCAN callback',
+                'Recursion Level:    0',
                 'File Name:          clam.zip',
                 'File Type:          CL_TYPE_ZIP'
             ]