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 a3a3471b53d3bc052eef2ebc1c36bd674fac87ce Author: Peter Kovacs <[email protected]> AuthorDate: Sat Aug 1 16:18:19 2026 +0200 test(cppuhelper,binaryurp): wire the standalone qa GoogleTest suites Five more per-module qa suites onto `bazel test`, all green: //main/cppuhelper:cppuhelper_tests :cppuhelper_qa_ifcontainer (5) OInterfaceContainerHelper lifetime :cppuhelper_qa_unourl UnoUrl / UnoUrlDescriptor parsing :cppuhelper_qa_weak OWeakObject XWeak adapter + queryAdapted //main/binaryurp:binaryurp_tests :binaryurp_qa_cache Cache<T> LRU eviction :binaryurp_qa_unmarshal URP wire decoding Ports the dmake makefile.mk / GoogleTest_*.mk recipes. qa/unourl has no main.cxx of its own — dmake got main() from the gtest lib, so it takes @gtest//:gtest_main. binaryurp.dll exports only the two UNO component entry points, so neither binaryurp test can link it; both compile the code under test straight into the exe, matching GoogleTest_unmarshal.mk's object list (hence the module sources are hoisted into a shared _SRCS). NOT wired: cppuhelper/qa/propertysetmixin is a subsequent test (UNO component DLL + its own types.idl, driven from Java against a service manager), so it needs the OfficeConnection fixture rather than a standalone exe. Also corrects main/test/readme.md, which described //main/sal:sal_tests as a 22-target green gate with a list of exclusions. Neither holds: the suite is 36 targets and deliberately runs everything, red included (the rationale is next to the test_suite in main/sal/BUILD.bazel), and the rtl_str/rtl_ustr/rtl_string NULL-deref failures it listed were since fixed. Replaced with the 6 that actually fail today and why — each on its own merits, none a build or loader problem. Co-Authored-By: Claude Opus 5 <[email protected]> --- CLAUDE.md | 22 ++++++--- main/binaryurp/BUILD.bazel | 103 +++++++++++++++++++++++++++++++++++------ main/cppuhelper/BUILD.bazel | 106 ++++++++++++++++++++++++++++++++++++++++++ main/test/readme.md | 109 ++++++++++++++++++++++++++++++++++++-------- 4 files changed, 301 insertions(+), 39 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 85457c3915..63959e4f30 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,12 +39,22 @@ test 🔨 C++ unit-test infra runnable — NOW THE FRONT-LINE TASK: br //main/sal:sal_tests (22) via sal_qa_test macro, salhelper_test, comphelper_test_string + comphelper_test_weakbag, sax_test_converter, cppu_qa_{any,unotype,reference,recursion} (private types.idl → headers - via idl_library reuse). See main/test/readme.md. NEXT: sweep qa/ - across the other migrated modules (cppuhelper [5 subdirs], svl, - svtools, …; svl/qa/test_URIHelper bootstraps a UNO - component context → subsequent test, needs the soffice fixture, not - standalone); OfficeConnection (UNO subsequent) tests need a - running-soffice fixture; cppunit suites need Phase-4 dep. + via idl_library reuse), cppuhelper_tests (ifcontainer/unourl/weak), + binaryurp_tests (cache/unmarshal). See main/test/readme.md. + LANDMINE (cost a whole session): the C++/UNO bridge DLL + (msci_uno/mscx_uno) is a RUNTIME dep nothing links — cppu + osl_loadModule()s it from any Mapping (getCaughtException etc.). + Unstaged ⇒ either a null mapping AV or R6034 → 0xC0000142 with an + EMPTY test.log; and the CRT manifest must be EMBEDDED (RT_MANIFEST + id 1, now linked into every gtest_test exe) not just staged as an + external <exe>.manifest, or late DLL loads fall outside the + activation context. NEXT: sweep qa/ across the remaining migrated + modules — most of what is left is NOT standalone: svl/qa/complex + + svtools/qa/unoapi + sfx2 + writerfilter/qa/complex are Java/UNO, + svl/qa/test_URIHelper and configmgr/qa/unit bootstrap a UNO + component context, shell/qa + writerfilter/qa/cppunittests are + cppunit. So the front line now shifts to the two fixtures: + OfficeConnection (running-soffice) and a CppUnit external dep. 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/main/binaryurp/BUILD.bazel b/main/binaryurp/BUILD.bazel index 200abefe66..04cc970a5f 100644 --- a/main/binaryurp/BUILD.bazel +++ b/main/binaryurp/BUILD.bazel @@ -1,6 +1,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary") +load("//build/rules:gtest_test.bzl", "gtest_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -26,26 +27,28 @@ _DEPS = [ "@boost.legacy//:boost.legacy", ] +_SRCS = [ + "source/binaryany.cxx", + "source/bridge.cxx", + "source/bridgefactory.cxx", + "source/currentcontext.cxx", + "source/incomingrequest.cxx", + "source/lessoperators.cxx", + "source/marshal.cxx", + "source/outgoingrequests.cxx", + "source/proxy.cxx", + "source/reader.cxx", + "source/unmarshal.cxx", + "source/writer.cxx", +] + # ── binaryurp.dll ───────────────────────────────────────────────── # UNO bridge component. Exports component_getFactory and # component_getImplementationEnvironment via SAL_DLLPUBLIC_EXPORT — # no DEF file needed. cc_binary( name = "binaryurp", - srcs = [ - "source/binaryany.cxx", - "source/bridge.cxx", - "source/bridgefactory.cxx", - "source/currentcontext.cxx", - "source/incomingrequest.cxx", - "source/lessoperators.cxx", - "source/marshal.cxx", - "source/outgoingrequests.cxx", - "source/proxy.cxx", - "source/reader.cxx", - "source/unmarshal.cxx", - "source/writer.cxx", - ] + glob(["source/*.hxx"]), + srcs = _SRCS + glob(["source/*.hxx"]), copts = _COPTS, defines = _DEFINES, linkshared = True, @@ -66,5 +69,77 @@ cc_binary( visibility = ["//visibility:public"], ) +# ── qa unit tests ───────────────────────────────────────────────── +# Standalone GoogleTest exes (qa/main.cxx provides main()). Ports +# GoogleTest_cache.mk / GoogleTest_unmarshal.mk. +# +# binaryurp.dll exports ONLY the two UNO component entry points, so neither +# test can link against it — both compile the code under test straight into +# the exe. The tests reach into the module's private headers by relative +# path ("../source/cache.hxx"), which resolves from the qa/ source dir. + +# Cache<T> LRU eviction — header-only, sal + stl only (GoogleTest_cache.mk). +gtest_test( + name = "binaryurp_qa_cache", + srcs = [ + "qa/main.cxx", + "qa/test-cache.cxx", + "source/cache.hxx", + ], + copts = _COPTS, + defines = _DEFINES, + deps = _DEPS + ["//main/stlport:stlport"], + additional_linker_inputs = ["//main/sal:sal_implib"], + linkopts = ["$(execpath //main/sal:sal_implib)"], + runtime_dlls = ["//main/sal:sal3"], +) + +# Unmarshal — URP wire decoding. Pulls in the whole module (GoogleTest_ +# unmarshal.mk lists every binaryurp/source object) because Unmarshal ctor +# ties back to Bridge/Reader/Writer. +gtest_test( + name = "binaryurp_qa_unmarshal", + srcs = [ + "qa/main.cxx", + "qa/test-unmarshal.cxx", + ] + _SRCS + glob(["source/*.hxx"]), + copts = _COPTS, + defines = _DEFINES, + deps = _DEPS + ["//main/stlport:stlport"], + additional_linker_inputs = [ + "//main/sal:sal_implib", + "//main/salhelper:salhelper_implib", + "//main/cppu:cppu3_implib", + "//main/cppuhelper:cppuhelper_implib", + ], + linkopts = [ + "$(execpath //main/sal:sal_implib)", + "$(execpath //main/salhelper:salhelper_implib)", + "$(execpath //main/cppu:cppu3_implib)", + "$(execpath //main/cppuhelper:cppuhelper_implib)", + ], + # msci_uno/mscx_uno: nothing links it, but cppu osl_loadModule()s the + # C++↔UNO bridge on demand from any Mapping (getCaughtException, proxy + # marshalling). Unstaged ⇒ a stray copy off PATH loads its CRT outside + # this exe's activation context ⇒ R6034 ⇒ exit 0xC0000142. + runtime_dlls = [ + "//main/sal:sal3", + "//main/salhelper:salhelper3MSC", + "//main/cppu:cppu3", + "//main/cppuhelper:cppuhelper3MSC", + ] + select({ + "//build:arch_x64": ["//main/bridges:mscx_uno"], + "//conditions:default": ["//main/bridges:msci_uno"], + }), +) + +test_suite( + name = "binaryurp_tests", + tests = [ + ":binaryurp_qa_cache", + ":binaryurp_qa_unmarshal", + ], +) + exports_files(glob(["**/*.component"])) diff --git a/main/cppuhelper/BUILD.bazel b/main/cppuhelper/BUILD.bazel index 4cab9c74fa..be943453a4 100644 --- a/main/cppuhelper/BUILD.bazel +++ b/main/cppuhelper/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:idl_pipeline.bzl", "idl_library") +load("//build/rules:gtest_test.bzl", "gtest_test") _COPTS = [ "/Zm500", "/Zc:forScope", "/GR", "/nologo", "/Gs", @@ -118,3 +119,108 @@ filegroup( output_group = "interface_library", visibility = ["//visibility:public"], ) + +# ── qa unit tests ───────────────────────────────────────────────── +# Standalone GoogleTest exes (own main()) that link cppuhelper3MSC.dll's import +# lib. cppuhelper drags in sal3/cppu3/salhelper3MSC at run time, so all four +# DLLs must sit beside the staged exe (see //build/rules:gtest_test.bzl). +# +# The dmake makefiles also list $(TESTSHL2LIB) — a no-op, the variable is +# undefined since AOO retired testshl2 (see main/test/readme.md). +# +# NOT wired: qa/propertysetmixin — it is a *subsequent* test (builds a UNO +# component DLL + its own types.idl, driven from Java against a service +# manager), so it needs the OfficeConnection fixture, not a standalone exe. +_QA_COPTS = ["/Imain/cppuhelper/inc/pch"] + +_QA_DEPS = [ + ":cppuhelper_headers", + "//main/sal:sal_headers", + "//main/cppu:cppu_headers", + "//main/udkapi:udkapi_idl_headers", +] + +_QA_LINKER_INPUTS = [ + "//main/sal:sal_implib", + "//main/cppu:cppu3_implib", + ":cppuhelper_implib", +] + +_QA_LINKOPTS = [ + "$(execpath //main/sal:sal_implib)", + "$(execpath //main/cppu:cppu3_implib)", + "$(execpath :cppuhelper_implib)", +] + +# The C++/UNO bridge DLL is a RUN-TIME dep even though nothing links it: +# cppu::getCaughtException()/throwException() build a Mapping between the C++ +# and UNO environments, and cppu's uno_getMapping osl_loadModule()s the bridge +# (msci_uno.dll / mscx_uno.dll) on demand. Omit it and the loader either finds +# a stray copy elsewhere on PATH — whose CRT then loads outside the exe's +# activation context → R6034 → DllMain fails → exit 0xC0000142 — or finds +# nothing, leaving a null mapping that AVs inside dispose(). Same select() as +# //main/bridges:cppuno_roundtrip_test; the compiled CPPU_ENV picks the match. +_QA_RUNTIME_DLLS = [ + "//main/sal:sal3", + "//main/cppu:cppu3", + "//main/salhelper:salhelper3MSC", + ":cppuhelper3MSC", +] + select({ + "//build:arch_x64": ["//main/bridges:mscx_uno"], + "//conditions:default": ["//main/bridges:msci_uno"], +}) + +# cppu::OInterfaceContainerHelper / OMultiTypeInterfaceContainerHelper — +# listener add/remove/dispose lifetime (qa/ifcontainer). +gtest_test( + name = "cppuhelper_qa_ifcontainer", + srcs = [ + "qa/ifcontainer/cppu_ifcontainer.cxx", + "qa/ifcontainer/main.cxx", + ], + copts = _QA_COPTS, + defines = _DEFINES, + deps = _QA_DEPS, + additional_linker_inputs = _QA_LINKER_INPUTS, + linkopts = _QA_LINKOPTS, + runtime_dlls = _QA_RUNTIME_DLLS, +) + +# cppu::UnoUrl / UnoUrlDescriptor parsing (qa/unourl). This suite has no +# main.cxx of its own — dmake got main() from the gtest lib, so use +# @gtest//:gtest_main here. +gtest_test( + name = "cppuhelper_qa_unourl", + srcs = ["qa/unourl/cppu_unourl.cxx"], + copts = _QA_COPTS, + defines = _DEFINES, + deps = _QA_DEPS + ["@gtest//:gtest_main"], + additional_linker_inputs = _QA_LINKER_INPUTS, + linkopts = _QA_LINKOPTS, + runtime_dlls = _QA_RUNTIME_DLLS, +) + +# cppu::OWeakObject / WeakImplHelper — XWeak adapter + queryAdapted, incl. +# exceptions thrown out of dispose() (qa/weak). +gtest_test( + name = "cppuhelper_qa_weak", + srcs = [ + "qa/weak/main.cxx", + "qa/weak/test_weak.cxx", + ], + copts = _QA_COPTS, + defines = _DEFINES, + deps = _QA_DEPS, + additional_linker_inputs = _QA_LINKER_INPUTS, + linkopts = _QA_LINKOPTS, + runtime_dlls = _QA_RUNTIME_DLLS, +) + +test_suite( + name = "cppuhelper_tests", + tests = [ + ":cppuhelper_qa_ifcontainer", + ":cppuhelper_qa_unourl", + ":cppuhelper_qa_weak", + ], +) diff --git a/main/test/readme.md b/main/test/readme.md index 97391d6622..a4372343fb 100644 --- a/main/test/readme.md +++ b/main/test/readme.md @@ -1,3 +1,22 @@ +<!-- + 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. +--> + # C++ unit-test infrastructure — Bazel migration AOO's C++ tests are **GoogleTest 1.7.0**-based (not CppUnit, apart from a few @@ -7,10 +26,11 @@ holdouts). This brings the test layer onto Bazel so suites run under ## Pieces | Piece | Path | Role | -|-------|------|------| +| ----- | ---- | ---- | | `@gtest` | `ext_libraries/modules/gtest/1.7.0/` | GoogleTest 1.7.0 bzlmod wrap (zip cached in `ext_sources`). Built with `/Zc:wchar_t-` so its `wchar_t` ABI matches `sal_Unicode` test code. | | `gtest_test` rule | [//build/rules:gtest_test.bzl](../../build/rules/gtest_test.bzl) | Reusable runnable-test rule. The `/MD` toolchain embeds no manifest, so a bare `cc_test` exe can't launch (DLLs land in runfiles subdirs; loose CRT → R6034). This stages the exe + runtime DLLs + VC90 CRT + an external `<exe>.manifest` into ONE flat dir (the test analog of `//main/idl:svidl_bundle`). | | `libtest` | [//main/test:test](BUILD.bazel) | `test.dll` — `test::OfficeConnection` + arg/url helpers, for *subsequent* (UNO) tests that bootstrap a running soffice over URP. Built; not yet exercised. | +| `vc90_app_manifest_res` | [//main/external/msvcp90](../external/msvcp90/BUILD.bazel) | The VC90-CRT manifest compiled to a `.res` and linked into every `gtest_test` exe at `RT_MANIFEST` id 1. See "the CRT activation context" below. | | `sal_qa_test` macro | [//main/sal:sal_qa.bzl](../sal/sal_qa.bzl) | Thin `gtest_test` wrapper for the sal/qa suites (common copts/deps + per-dir `*_Const.h` include). | ## Two test categories @@ -25,6 +45,10 @@ holdouts). This brings the test layer onto Bazel so suites run under - `//main/sax:sax_test_converter` - `//main/cppu:cppu_qa_any` / `:cppu_qa_unotype` / `:cppu_qa_reference` / `:cppu_qa_recursion` + - `//main/cppuhelper:cppuhelper_tests` — `:cppuhelper_qa_ifcontainer` (5), + `:cppuhelper_qa_unourl`, `:cppuhelper_qa_weak` + - `//main/binaryurp:binaryurp_tests` — `:binaryurp_qa_cache`, + `:binaryurp_qa_unmarshal` **Tests with private IDL types** (cppu/qa has a `types.idl` defining Enum1/Struct1/Interface1/… used only by the tests): reuse the `idl_library` @@ -47,6 +71,44 @@ holdouts). This brings the test layer onto Bazel so suites run under ## Gotchas (learned the hard way) +- **The C++/UNO bridge DLL is a run-time dep that nothing links.** + `cppu::getCaughtException()` / `cppu::throwException()` — reached from any + `OWeakObject` dispose path, `OInterfaceContainerHelper`, proxy marshalling — + construct a `Mapping` between the C++ and UNO environments, and cppu's + `uno_getMapping` **`osl_loadModule()`s the bridge on demand** + (`msci_uno.dll` on x86, `mscx_uno.dll` on x64; `lbmap.cxx::loadModule`). + It is invisible to the linker, so it must be listed in `runtime_dlls`: + + ```starlark + runtime_dlls = [...] + select({ + "//build:arch_x64": ["//main/bridges:mscx_uno"], + "//conditions:default": ["//main/bridges:msci_uno"], + }) + ``` + + Omit it and you get one of two confusing failures — neither of which names + the bridge: + - the mapping comes back **null** and the test AVs (SEH `0xc0000005`) deep + inside `dispose()`, looking like a source bug (this is what + `cppuhelper_qa_weak` did); + - or the loader finds a *stray* copy elsewhere on `PATH`, whose CRT then + loads outside the exe's activation context → **R6034** → `DllMain` fails → + the process dies with `0xC0000142` (`STATUS_DLL_INIT_FAILED`) before gtest + prints a single line, so `test.log` is **empty**. + +- **The CRT activation context must be embedded, not external.** The staged + `<exe>.manifest` only reliably covers DLLs bound at process start. A test + that `osl_loadModule()`s a UNO DLL *later* needs the context still in force, + so `gtest_test` links `//main/external/msvcp90:vc90_app_manifest_res` into + every exe (`RT_MANIFEST` id 1, which the loader always honours and which + supersedes the external file). `//main/bridges:jni_test_launcher` hit the + same wall with the DLLs a hosted JVM loads and fixed it the same way. + Symptom without it: R6034 / `0xC0000142` under `bazel test` while the very + same exe run by hand from a shell passes — the discriminator is the + environment, not the binary, so it is easy to misread as flakiness. + (Not yet handled: under `--compilation_mode=dbg` the exes link `/MDd` but + this `.res` still carries the *release* CRT manifest.) + - **`/Zc:wchar_t-` must be consistent across gtest and every test TU.** gtest declares `PrintTo(wchar_t)`; with `/Zc:wchar_t-` (`wchar_t == unsigned short`) on one side only, that mangles vs `PrintTo(unsigned short)` → `LNK2019`. Fixed @@ -63,25 +125,34 @@ holdouts). This brings the test layer onto Bazel so suites run under won't build at all). Don't be fooled by the half-fix: `/FIwindows.h` + advapi32 satisfies its Win32 SID/registry calls but not the testshl2 include. -## Excluded from the sal green gate +## The sal suite is deliberately NOT a green gate + +`//main/sal:sal_tests` runs **every** migrated self-contained sal/qa test — 36 +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, 30 pass and these 6 fail, each on its **own merits** — +none is a build or loader problem, and the source is out of scope: -Wired and individually runnable, but kept out of `//main/sal:sal_tests` because -they fail on their own merits (source is out of scope, so not fixed): +| Target | Failing | Why | +| ------ | ------- | --- | +| `osl_File` | 10 | Assert on a specific drive topology (CD/floppy/RAM disk) absent here | +| `osl_Module` | 7 | Loads a module by path; depends on the dmake `solver/bin` layout | +| `tcwf` | 1 | `osl_writeFile` to a fixed path — permission bound | +| `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` | -- `rtl_str` / `rtl_ustr` / `rtl_string` / `rtl_OUString2` — `*_000` cases pass - `NULL` into `rtl_*_compare` etc., which dereference it → `0xC0000005`. -- `testHelperFunctions` — `test_t_abs64` computes `(2147483648 << 1)` in 32-bit - → overflow to 0 (test-logic bug on this platform). -- `rtl_logfile` — writes/reads `c:/temp` and asserts on it (env/permission). -- `rtl_textcvt` — text-conversion / mime / codepage table expectations - (sal's conversion works in the running app; this is test-data drift). -- `osl_File` — builds (`/FIwindows.h`) but 10/208 cases assert on a specific - drive topology (CD/floppy/RAM disk) absent on the test machine; the rest pass. +Earlier revisions of this file listed `rtl_str`/`rtl_ustr`/`rtl_string` as +NULL-deref crashes; those were since fixed (boundary checks in the tests plus +`NULL` guards at the rtl entry points) and now pass. -(`osl_Security` is NOT here — it fails to *build* on testshl2, see the gotcha -above; it's unwired entirely, not a green-gate exclusion.) +(`osl_Security` is not in the suite at all — it fails to *build* on testshl2, +see the gotcha above; it is unwired entirely, not an exclusion.) -Also deferred: cppunit suites (`osl/socket`, `rtl_strings`) → need a CppUnit -external dep; child-process tests (`osl/process`, `rtl/bootstrap`, `rtl/process`) -→ need helper-exe staging; resource/IPC tests (`osl/file`, `osl/module`, -`osl/pipe`); `systools/test_comtools` (COM init). +Still unwired: cppunit suites (`osl/socket`, `rtl_strings`) → need a CppUnit +external dep; child-process tests (`osl/process`, `rtl/bootstrap`, +`rtl/process`) → they resolve their helper exe via `getExecutablePath()`+`"/../bin"` +(the dmake `solver/bin` layout), which flat Bazel staging can't satisfy without +source changes — `gtest_test` has a `companions` hook ready for when that layout +is reproduced.
