This is an automated email from the ASF dual-hosted git repository.

leginee pushed a commit to branch bazel-migration
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 1172fcd4dd132ef65057c64589904ea280941fdb
Author: Peter Kovacs <[email protected]>
AuthorDate: Sun Aug 2 00:41:10 2026 +0200

    test: wire sal/strings, sw, sfx2, desktop suites; fix System32 icuuc 
shadowing
    
    Four more suites, and the loader landmine that blocked two of them.
    
      //main/sal:qa_rtl_strings          5 TUs -> one exe (NOT qa/rtl_strings, 
which
                                        is testshl dead weight; this is 
qa/rtl/strings)
      //main/sw:sw_qa_bigpointerarray    26 cases, BigPtrArray behind SwNodes
      //main/sfx2:sfx2_qa_metadatable    Metadatable / XmlIdRegistry
      //main/desktop:desktop_qa_dp_version  extension version ordering
    
    sw and sfx2 both died at load with STATUS_ENTRYPOINT_NOT_FOUND (0xC0000139) 
and
    an EMPTY test log.  Cause: C:\Windows\System32\icuuc.dll (a ~36 KB Microsoft
    stub) SHADOWS the ICU 49.1.2 icuuc.dll (~1.3 MB) that AOO bundles, and 
putting
    program/ on PATH does not help — the Windows loader searches System32 
BEFORE the
    working directory and PATH.  Anything importing icuuc transitively (sw.dll,
    sfx.dll, …) therefore binds the system one, whose exports do not match.
    soffice.exe never hits this because it lives in program/ beside our copy, 
and the
    exe's OWN directory is the one location searched ahead of System32.
    
    Fix: when uno_install is set, gtest_test co-locates the ICU DLLs with the 
test
    exe, mirroring what makes soffice.exe work.  Diffing all 248 staged DLL 
basenames
    against System32 shows icuuc.dll is the ONLY collision; the other two ICU 
DLLs
    are staged with it to keep the loaded ICU coherent.
    
    Empty test.log + a load-time exit code now has two known causes, worth 
telling
    apart: 0xC0000139 = a DLL loaded but an export was missing (wrong DLL won 
the
    search); 0xC0000142 = DllMain failed (the CRT activation-context / R6034 
case).
    
    uno_install is also documented now as doing double duty: besides the UNO
    bootstrap it puts the whole office DLL closure on PATH, which is far better 
than
    enumerating dozens of transitive DLLs in runtime_dlls for anything linking a
    library the size of sw.dll or sfx.dll.  Per the project's stated position, 
the
    resulting full-install dependency is not a reason to skip wiring a test — a 
slow
    test beats no test.
    
    Test layer: 61 -> 66 targets, 55 passing.  The 11 failures are the 10 
already
    documented in main/test/readme.md plus qa_rtl_strings' 
Convert.convertToString,
    which is the same text-conversion drift as rtl_textcvt / rtl_OUString2.  No
    regressions from the ICU change.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
---
 CLAUDE.md                  | 20 +++++++++++++++++
 build/rules/gtest_test.bzl | 55 +++++++++++++++++++++++++++++++++++++---------
 main/desktop/BUILD.bazel   | 34 ++++++++++++++++++++++++++++
 main/sal/BUILD.bazel       | 16 ++++++++++++++
 main/sfx2/BUILD.bazel      | 40 ++++++++++++++++++++++++++++++++-
 main/sw/BUILD.bazel        | 34 ++++++++++++++++++++++++++++
 main/test/readme.md        | 29 ++++++++++++++++++++++--
 7 files changed, 215 insertions(+), 13 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 56abcffa12..a913554291 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -83,6 +83,26 @@ test          🔨  C++ unit-test infra runnable — NOW THE 
FRONT-LINE TASK: br
                    LANDMINE for any new launcher: bazel test's CWD is NEITHER 
the exe
                    dir NOR the execroot — locate everything from %~dp0 (see
                    _windows_relpath in gtest_test.bzl).
+                   LANDMINE (icu): C:\Windows\System32\icuuc.dll SHADOWS our 
bundled
+                   ICU 49 icuuc.dll, and PATH cannot beat it — System32 is 
searched
+                   before CWD/PATH.  Anything importing it (sw.dll, sfx.dll…) 
dies at
+                   load with STATUS_ENTRYPOINT_NOT_FOUND 0xC0000139 + an EMPTY
+                   test.log; soffice.exe is immune only because it sits in 
program/
+                   next to our copy.  gtest_test co-locates the ICU DLLs with 
the test
+                   exe when uno_install is set.  icuuc is the ONLY collision 
among the
+                   248 staged DLLs.  Empty-log triage: 0xC0000139 = wrong DLL 
won the
+                   search; 0xC0000142 = DllMain failed (CRT activation ctx).
+                   Wired since: sal qa_rtl_strings, sw_qa_bigpointerarray,
+                   sfx2_qa_metadatable, desktop_qa_dp_version.  uno_install 
doubles as
+                   "give me the whole office DLL closure on PATH", which beats
+                   enumerating dozens of transitive DLLs for sw/sfx-sized 
libraries.
+                   STILL TODO in this sweep: configmgr/qa/unit (builds its OWN 
mini
+                   installation — urebootstrap.ini + data.xcd + generated inis 
— so it
+                   needs a genrule, not //main/staging:install), cppuhelper/qa/
+                   propertysetmixin (UNO component DLL + own types.idl + 
services.rdb),
+                   xmlsecurity/qa/certext + sal child-process suites 
(osl/process,
+                   rtl/bootstrap, rtl/process) which need OfficeConnection / 
companion
+                   staging, and writerfilter doctok.
 testtools     ⬜  (bridgetest — pure-C++ UNO bridge round-trip; cli/pyuno/java 
variants
                    need rules_java — see Java bucket)
 qadevOOo      🔨  OOoRunner.jar built (//main/qadevOOo:OOoRunner — qadevOOo QA
diff --git a/build/rules/gtest_test.bzl b/build/rules/gtest_test.bzl
index 2f3b6eacf6..1424e1b272 100644
--- a/build/rules/gtest_test.bzl
+++ b/build/rules/gtest_test.bzl
@@ -62,17 +62,26 @@ def _windows_relpath(from_dir, to_dir):
 def _staged_gtest_test_impl(ctx):
     d = ctx.label.name + ".run"
     staged = []
+    seen = {}
+
+    def stage(f, name = None):
+        name = name or f.basename
+        if name in seen:
+            return
+        seen[name] = True
+        o = ctx.actions.declare_file(d + "/" + name)
+        ctx.actions.symlink(output = o, target_file = f)
+        staged.append(o)
 
     # The gtest exe, renamed to the test target's name.
     staged_exe = ctx.actions.declare_file(d + "/" + ctx.label.name + ".exe")
     ctx.actions.symlink(output = staged_exe, target_file = 
ctx.executable.binary)
+    seen[staged_exe.basename] = True
     staged.append(staged_exe)
 
     # Runtime DLLs + VC90 CRT (msvcr90/msvcp90/msvcm90 + 
Microsoft.VC90.CRT.manifest).
     for f in ctx.files.runtime:
-        o = ctx.actions.declare_file(d + "/" + f.basename)
-        ctx.actions.symlink(output = o, target_file = f)
-        staged.append(o)
+        stage(f)
 
     # Companion helper exes (e.g. a child process the test spawns by name).
     # Staged under their own basename + a matching <name>.exe.manifest so they
@@ -105,8 +114,8 @@ def _staged_gtest_test_impl(ctx):
     # The install root is a fixed bazel-out path (tree_install declares its
     # outputs in //main/staging), so locating program/fundamental.ini among the
     # install files at analysis time yields the execroot-relative program dir.
-    # `bazel test` runs with the working directory set to the execroot, hence
-    # %CD% below.
+    # The launcher then reaches it from its OWN location (%~dp0) — see
+    # _windows_relpath; never from %CD%, which is not the execroot.
     uno_program_dir = None
     for f in ctx.files.uno_install:
         if f.path.endswith("/program/fundamental.ini"):
@@ -115,6 +124,26 @@ def _staged_gtest_test_impl(ctx):
     if ctx.files.uno_install and uno_program_dir == None:
         fail("uno_install does not contain program/fundamental.ini — is it 
//main/staging:install?")
 
+    # System32 SHADOWS one of our staged DLLs, and putting program/ on PATH 
does
+    # NOT beat it: the Windows loader searches System32 *before* the working
+    # directory and PATH.  Windows ships its own C:\Windows\System32\icuuc.dll 
(a
+    # ~36 KB stub) while AOO bundles ICU 49.1.2 (~1.3 MB); everything importing
+    # icuuc — sw.dll, sfx.dll, … — then binds the system one, whose exports do
+    # not match, and the process dies at load with STATUS_ENTRYPOINT_NOT_FOUND
+    # (0xC0000139) and an EMPTY test log.  soffice.exe is immune only because 
it
+    # lives in program/ next to our copy, and the exe's own directory IS 
searched
+    # first.  So mirror that: co-locate ICU with the test exe.
+    # icuuc.dll is the only one of the 248 staged DLLs that collides; the other
+    # two come along to keep the loaded ICU coherent.
+    if uno_program_dir:
+        for f in ctx.files.uno_install:
+            if f.dirname == uno_program_dir and f.basename in [
+                "icuuc.dll",
+                "icui18n.dll",
+                "icudata.dll",
+            ]:
+                stage(f)
+
     executable = staged_exe
     if ctx.attr.run_in_staged_dir or uno_program_dir:
         launcher_dir = staged_exe.dirname  # the .bat sits beside the staged 
exe
@@ -197,11 +226,17 @@ def gtest_test(
     directory set to that staged dir, which co-location alone does not give you
     (see run_in_staged_dir in the staging rule).
 
-    uno_install: for *subsequent* tests that call
-    cppu::defaultBootstrap_InitialComponentContext(). Pass
-    //main/staging:install; the test then runs against that staged office via
-    URE_BOOTSTRAP. Note this makes the test depend on the whole install, so it
-    is far from a unit test — keep it off targets that don't need UNO.
+    uno_install: run the test INSIDE the staged office install (pass
+    //main/staging:install). Two independent things come from this, and either
+    one alone is a good enough reason to use it:
+      * a UNO bootstrap — URE_BOOTSTRAP is exported, so a test that calls
+        cppu::defaultBootstrap_InitialComponentContext() gets a real component
+        context (the *subsequent* test case);
+      * the whole office DLL closure on PATH — which beats enumerating dozens 
of
+        transitive DLLs in runtime_dlls for anything linking a big library like
+        sfx.dll or sw.dll.
+    It does make the test depend on the entire install, but a slow test beats 
no
+    test; build time is not a reason to skip wiring something.
     """
     cc_binary(
         name = name + "_bin",
diff --git a/main/desktop/BUILD.bazel b/main/desktop/BUILD.bazel
index 1f96cab28d..a28069f59b 100644
--- a/main/desktop/BUILD.bazel
+++ b/main/desktop/BUILD.bazel
@@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"])
 
 load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
 load("//build/rules:rsc_pipeline.bzl", "rsc_res")
+load("//build/rules:gtest_test.bzl", "gtest_test")
 
 # ── Common compile settings 
───────────────────────────────────────────────────
 _DEFINES = [
@@ -1152,3 +1153,36 @@ exports_files(["util/soffice.exe.manifest", 
"util/soffice.bin.manifest"])
 # this variant.  Same basename so it still stages as soffice.exe/bin.manifest.
 exports_files(["util/amd64/soffice.exe.manifest"])
 
+
+# ── qa unit test ──────────────────────────────────────────────────
+# dp_misc::compareVersions — extension version ordering (qa/deployment_misc).
+# Ports qa/deployment_misc/makefile.mk (gtest + deploymentmisc + sal).
+# DISABLE_PCH_HACK comes from that makefile's CFLAGSCXX.
+gtest_test(
+    name = "desktop_qa_dp_version",
+    srcs = [
+        "qa/deployment_misc/test_dp_version.cxx",
+        "qa/deployment_misc/main.cxx",
+    ],
+    copts = _COPTS,
+    defines = _DEFINES + ["DISABLE_PCH_HACK"],
+    deps = [
+        ":desktop_source_inc_hdrs",
+        "//main/sal:sal_headers",
+        "//main/cppu:cppu_headers",
+        "//main/cppuhelper:cppuhelper_headers",
+        "//main/udkapi:udkapi_idl_headers",
+        "//main/offapi:offapi_idl_headers",
+        "//main/stlport:stlport",
+        "@boost.legacy//:boost.legacy",
+    ],
+    additional_linker_inputs = [
+        "//main/sal:sal_implib",
+        ":deploymentmisc_implib",
+    ],
+    linkopts = [
+        "$(execpath //main/sal:sal_implib)",
+        "$(execpath :deploymentmisc_implib)",
+    ],
+    uno_install = "//main/staging:install",
+)
diff --git a/main/sal/BUILD.bazel b/main/sal/BUILD.bazel
index bd001a851f..ee152cc1f3 100644
--- a/main/sal/BUILD.bazel
+++ b/main/sal/BUILD.bazel
@@ -327,6 +327,21 @@ sal_qa_test(
     srcs = ["qa/testHelperFunctions/testHelperFunctions.cxx", 
"qa/testHelperFunctions/testHelperFunctions2.cxx"],
     subdir = "testHelperFunctions",
 )
+# qa/rtl/strings — one exe from 5 TUs (test_oustring_noadditional.cxx supplies
+# main()).  NOT the same thing as qa/rtl_strings, which is testshl-based dead
+# weight superseded by qa/rtl/{ostring,oustring}; this one is plain GoogleTest.
+sal_qa_test(
+    name = "qa_rtl_strings",
+    srcs = [
+        "qa/rtl/strings/test_oustringbuffer_utf32.cxx",
+        "qa/rtl/strings/test_oustring_compare.cxx",
+        "qa/rtl/strings/test_oustring_convert.cxx",
+        "qa/rtl/strings/test_oustring_endswith.cxx",
+        "qa/rtl/strings/test_oustring_noadditional.cxx",
+    ],
+    subdir = "rtl/strings",
+)
+
 sal_qa_test(name = "sal_ut_types", srcs = ["qa/sal/test_types.cxx"], subdir = 
"sal")
 sal_qa_test(name = "sal_ut_bytesequence", srcs = 
["qa/ByteSequence/ByteSequence.cxx"], subdir = "ByteSequence")
 
@@ -384,6 +399,7 @@ test_suite(
         ":tcwf",
         ":osl_old_test_file",
         ":osl_Thread",
+        ":qa_rtl_strings",
         ":osl_SocketOld",
         ":osl_Socket_tests",
         ":osl_StreamSocket",
diff --git a/main/sfx2/BUILD.bazel b/main/sfx2/BUILD.bazel
index 43df0687f3..ce4791aa23 100644
--- a/main/sfx2/BUILD.bazel
+++ b/main/sfx2/BUILD.bazel
@@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"])
 load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
 load("//build/rules:rsc_pipeline.bzl", "rsc_res")
 load("//build/rules:sdi_target.bzl", "sdi_package", "sdi_target")
+load("//build/rules:gtest_test.bzl", "gtest_test")
 
 _DEFINES = [
     "WNT", "GUI", "WIN32",
@@ -226,4 +227,41 @@ rsc_res(
     visibility  = ["//visibility:public"],
 )
 
-exports_files(glob(["**/*.component"]))
\ No newline at end of file
+exports_files(glob(["**/*.component"]))
+# ── qa unit test ──────────────────────────────────────────────────
+# sfx2::Metadatable / XmlIdRegistry — RDF metadata identity and the
+# copy/undo bookkeeping around it (qa/gtest/test_metadatable.cxx).
+# Ports GoogleTest_sfx2_metadatable.mk (cppu cppuhelper sal sfx stl).
+gtest_test(
+    name = "sfx2_qa_metadatable",
+    srcs = ["qa/gtest/test_metadatable.cxx"],
+    copts = _COPTS,
+    defines = _DEFINES,
+    deps = [
+        ":sfx2_headers",
+        "//main/sal:sal_headers",
+        "//main/cppu:cppu_headers",
+        "//main/cppuhelper:cppuhelper_headers",
+        "//main/udkapi:udkapi_idl_headers",
+        "//main/offapi:offapi_idl_headers",
+        "//main/stlport:stlport",
+        "@boost.legacy//:boost.legacy",
+    ],
+    additional_linker_inputs = [
+        "//main/sal:sal_implib",
+        "//main/cppu:cppu3_implib",
+        "//main/cppuhelper:cppuhelper_implib",
+        ":sfx_implib",
+    ],
+    linkopts = [
+        "$(execpath //main/sal:sal_implib)",
+        "$(execpath //main/cppu:cppu3_implib)",
+        "$(execpath //main/cppuhelper:cppuhelper_implib)",
+        "$(execpath :sfx_implib)",
+    ],
+    # Not a UNO-bootstrapping test, but sfx.dll's transitive DLL closure is
+    # enormous (svl, svtools, tools, vcl, comphelper, ucbhelper, …).  Running
+    # inside the staged install supplies all of it via PATH instead of making 
us
+    # enumerate it in runtime_dlls.
+    uno_install = "//main/staging:install",
+)
diff --git a/main/sw/BUILD.bazel b/main/sw/BUILD.bazel
index cb8d873536..bf76cb8804 100644
--- a/main/sw/BUILD.bazel
+++ b/main/sw/BUILD.bazel
@@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"])
 load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
 load("//build/rules:rsc_pipeline.bzl", "rsc_res")
 load("//build/rules:sdi_target.bzl", "sdi_target")
+load("//build/rules:gtest_test.bzl", "gtest_test")
 
 _DEFINES = [
     "WNT", "GUI", "WIN32",
@@ -1510,3 +1511,36 @@ filegroup(
 
 exports_files(glob(["**/*.component"]))
 
+
+# ── qa unit test ──────────────────────────────────────────────────
+# BigPtrArray — the block-pointer array behind SwNodes (qa/core).
+# Ports GoogleTest_sw_bigpointerarray.mk (sal sfx stl sw tl).
+gtest_test(
+    name = "sw_qa_bigpointerarray",
+    srcs = ["qa/core/Test-BigPtrArray.cxx"],
+    copts = _COPTS + ["/Imain/sw/qa/core"],
+    defines = _DEFINES,
+    deps = [
+        ":sw_headers",
+        "//main/sal:sal_headers",
+        "//main/tools:tools_headers",
+        "//main/sfx2:sfx2_headers",
+        "//main/udkapi:udkapi_idl_headers",
+        "//main/offapi:offapi_idl_headers",
+        "//main/stlport:stlport",
+        "@boost.legacy//:boost.legacy",
+    ],
+    additional_linker_inputs = [
+        "//main/sal:sal_implib",
+        "//main/tools:tl_implib",
+        ":sw_implib",
+    ],
+    linkopts = [
+        "$(execpath //main/sal:sal_implib)",
+        "$(execpath //main/tools:tl_implib)",
+        "$(execpath :sw_implib)",
+    ],
+    # sw.dll drags in most of the office; run inside the staged install rather
+    # than enumerating the closure (see gtest_test's uno_install).
+    uno_install = "//main/staging:install",
+)
diff --git a/main/test/readme.md b/main/test/readme.md
index b7aa4773d1..6ca14e2658 100644
--- a/main/test/readme.md
+++ b/main/test/readme.md
@@ -51,6 +51,10 @@ holdouts).  This brings the test layer onto Bazel so suites 
run under
    - `//main/binaryurp:binaryurp_tests` — `:binaryurp_qa_cache`,
      `:binaryurp_qa_unmarshal`
    - `//main/shell:shell_qa_zip` (3) — zipfile reader over a real `.odt`
+   - `//main/sal:qa_rtl_strings` (5 TUs, one exe)
+   - `//main/sw:sw_qa_bigpointerarray` (26) — `BigPtrArray` behind `SwNodes`
+   - `//main/sfx2:sfx2_qa_metadatable` — `Metadatable` / `XmlIdRegistry`
+   - `//main/desktop:desktop_qa_dp_version` — extension version ordering
    - `//main/sal:osl_Socket_tests`, `:osl_StreamSocket`, `:osl_DatagramSocket`,
      `:osl_AcceptorSocket` (4 of the 8 socket suites; see the socket note 
below)
 
@@ -143,6 +147,26 @@ holdouts).  This brings the test layer onto Bazel so 
suites run under
   (Not yet handled: under `--compilation_mode=dbg` the exes link `/MDd` but
   this `.res` still carries the *release* CRT manifest.)
 
+- **System32 shadows our bundled `icuuc.dll`, and `PATH` cannot beat it.** The
+  Windows loader searches `System32` *before* the working directory and `PATH`.
+  Windows ships a ~36 KB `C:\Windows\System32\icuuc.dll`; AOO bundles ICU 
49.1.2
+  (~1.3 MB) under the same name. Any test exe importing it transitively —
+  anything linking `sw.dll`, `sfx.dll`, … — therefore binds the *system* one,
+  whose exports don't match, and dies at load with 
**`STATUS_ENTRYPOINT_NOT_FOUND`
+  (`0xC0000139`)** and an **empty test log**. `soffice.exe` never hits this
+  because it lives in `program/` next to our copy, and the exe's OWN directory 
is
+  the one thing searched ahead of `System32`.
+
+  `gtest_test` handles it: when `uno_install` is set it co-locates the ICU DLLs
+  with the test exe. `icuuc.dll` is the only collision among the 248 staged 
DLLs
+  (verified by diffing basenames against `System32`); the other two ICU DLLs 
are
+  staged with it to keep the loaded ICU coherent.
+
+  Triage note: this and the R6034 bridge landmine both present as *empty
+  test.log + a load-time exit code*. `0xC0000139` = a DLL loaded but an export
+  was missing (wrong DLL won the search); `0xC0000142` = `DllMain` failed (the
+  CRT activation-context case).
+
 - **Never assume the test's working directory.** It is *not* the exe's
   directory, and it is *not* the execroot either — a launcher that built paths
   from `%CD%` produced "The system cannot find the path specified" even though
@@ -179,11 +203,11 @@ holdouts).  This brings the test layer onto Bazel so 
suites run under
 
 ## The sal suite is deliberately NOT a green gate
 
-`//main/sal:sal_tests` runs **every** migrated self-contained sal/qa test — 44
+`//main/sal:sal_tests` runs **every** migrated self-contained sal/qa test — 45
 targets, passing and failing alike, on the principle that failures are
 information, not something to hide (the rationale lives next to the
 `test_suite` in [main/sal/BUILD.bazel](../sal/BUILD.bazel)). So expect it to be
-red. As of 2026-08-01, 34 pass and these 10 fail, each on its **own merits** —
+red. As of 2026-08-02, 34 pass and these 11 fail, each on its **own merits** —
 none is a build or loader problem, and the source is out of scope:
 
 | Target | Failing | Why |
@@ -194,6 +218,7 @@ none is a build or loader problem, and the source is out of 
scope:
 | `rtl_logfile` | 1 | Writes/reads `c:/temp` and asserts on it — 
env/permission bound |
 | `osl_Thread` | 1 | `resume_001` is a timing race; flaky, not deterministic |
 | `rtl_OUString2` | 1 | `convertFromString` expects `\x80` to fail UTF-8 
validation — test-data drift, same class as `rtl_textcvt` |
+| `qa_rtl_strings` | 1 | `Convert.convertToString` — same text-conversion 
drift |
 | `osl_SocketOld` | 10 | see socket note below |
 | `osl_SocketAddr` | 3 | see socket note below |
 | `osl_Socket2` | 7 | see socket note below |

Reply via email to