include/test/bootstrapfixture.hxx | 9 - include/test/unoapi_test.hxx | 9 + test/source/bootstrapfixture.cxx | 162 ----------------------------------- test/source/unoapi_test.cxx | 172 +++++++++++++++++++++++++++++++++++++- 4 files changed, 180 insertions(+), 172 deletions(-)
New commits: commit 6985cb97b691b56a9474e81ff8f130440e5e2d38 Author: Xisco Fauli <[email protected]> AuthorDate: Tue Feb 3 12:02:08 2026 +0100 Commit: Xisco Fauli <[email protected]> CommitDate: Tue Feb 3 16:50:18 2026 +0100 BootstrapFixture: move validate to UnoApiTest and adapt it a bit it's the only place where it's used Change-Id: Iaf74e959dcedc27ab1781157e1d2f01a41be5e8c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198590 Tested-by: Jenkins Reviewed-by: Xisco Fauli <[email protected]> diff --git a/include/test/bootstrapfixture.hxx b/include/test/bootstrapfixture.hxx index e310cb1948a3..8302ff81d80a 100644 --- a/include/test/bootstrapfixture.hxx +++ b/include/test/bootstrapfixture.hxx @@ -18,13 +18,6 @@ namespace test { -enum ValidationFormat -{ - OOXML, - ODF, - MSBINARY -}; - // Class to do lots of heavy-lifting UNO & environment // bootstrapping for unit tests, such that we can use // almost an entire LibreOffice during compile - so @@ -53,8 +46,6 @@ public: virtual void setUp() override; - void validate(const OUString& rURL, std::u16string_view rFilter) const; - // Allows to exclude tests dependent on color depth of the default virtual device static sal_uInt16 getDefaultDeviceBitCount(); }; diff --git a/include/test/unoapi_test.hxx b/include/test/unoapi_test.hxx index ba7584d7cee1..6e21933395a0 100644 --- a/include/test/unoapi_test.hxx +++ b/include/test/unoapi_test.hxx @@ -22,6 +22,13 @@ #include <unotools/tempfile.hxx> #include <vcl/filter/PDFiumLibrary.hxx> +enum ValidationFormat +{ + OOXML, + ODF, + MSBINARY +}; + enum class TestFilter { NONE, @@ -171,6 +178,8 @@ private: void setTestInteractionHandler(const char* pPassword, std::vector<css::beans::PropertyValue>& rFilterOptions); + void validate(const OUString& rURL, TestFilter eFilter) const; + bool mbSkipValidation; OUString m_aBaseString; OUString maFilterOptions; diff --git a/test/source/bootstrapfixture.cxx b/test/source/bootstrapfixture.cxx index 39f2538ca10b..5ef50f0c2c34 100644 --- a/test/source/bootstrapfixture.cxx +++ b/test/source/bootstrapfixture.cxx @@ -24,7 +24,6 @@ #include <vcl/graphicfilter.hxx> #include <osl/file.hxx> #include <osl/process.h> -#include <unotest/getargument.hxx> #include <unotools/tempfile.hxx> #include <vcl/salgtype.hxx> #include <vcl/scheduler.hxx> @@ -119,167 +118,6 @@ test::BootstrapFixture::~BootstrapFixture() { } -#if HAVE_EXPORT_VALIDATION -namespace { - -OString loadFile(const OUString& rURL) -{ - osl::File aFile(rURL); - osl::FileBase::RC eStatus = aFile.open(osl_File_OpenFlag_Read); - CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, eStatus); - sal_uInt64 nSize; - aFile.getSize(nSize); - std::unique_ptr<char[]> aBytes(new char[nSize]); - sal_uInt64 nBytesRead; - aFile.read(aBytes.get(), nSize, nBytesRead); - CPPUNIT_ASSERT_EQUAL(nSize, nBytesRead); - OString aContent(aBytes.get(), nBytesRead); - - return aContent; -} - -constexpr std::u16string_view grand_total = u"Grand total of errors in submitted package: "; - -} -#endif - -void test::BootstrapFixture::validate(const OUString& rPath, std::u16string_view rFilter) const -{ - test::ValidationFormat eFormat = test::ODF; - if (rFilter == u"Calc Office Open XML") - eFormat = test::OOXML; - else if (rFilter == u"Office Open XML Text") - eFormat = test::OOXML; - else if (rFilter == u"Impress Office Open XML") - eFormat = test::OOXML; - else if (rFilter == u"writer8") - eFormat = test::ODF; - else if (rFilter == u"calc8") - eFormat = test::ODF; - else if (rFilter == u"impress8") - eFormat = test::ODF; - else if (rFilter == u"draw8") - eFormat = test::ODF; - else if (rFilter == u"MS Word 97") - eFormat = test::MSBINARY; - else if (rFilter == u"MS Excel 97") - eFormat = test::MSBINARY; - else if (rFilter == u"MS PowerPoint 97") - eFormat = test::MSBINARY; - else - { - SAL_INFO("test", "BootstrapFixture::validate: unknown filter"); - return; - } - -#if HAVE_EXPORT_VALIDATION - OUString var; - if( eFormat == test::OOXML ) - { - var = "OFFICEOTRON"; - } - else if ( eFormat == test::ODF ) - { - var = "ODFVALIDATOR"; - } - else if ( eFormat == test::MSBINARY ) - { -#if HAVE_BFFVALIDATOR - var = "BFFVALIDATOR"; -#else - // Binary Format Validator is disabled - return; -#endif - } - OUString aValidator; - oslProcessError e = osl_getEnvironment(var.pData, &aValidator.pData); - CPPUNIT_ASSERT_EQUAL_MESSAGE( - OUString("cannot get env var " + var).toUtf8().getStr(), - osl_Process_E_None, e); - CPPUNIT_ASSERT_MESSAGE( - OUString("empty get env var " + var).toUtf8().getStr(), - !aValidator.isEmpty()); - - if (eFormat == test::ODF) - { - // invoke without -e so that we know when something new is written - // in loext namespace that isn't yet in the custom schema - aValidator += " -M " - + m_directories.getPathFromSrc(u"/schema/libreoffice/OpenDocument-v1.4+libreoffice-manifest-schema.rng") - + " -D " - + m_directories.getPathFromSrc(u"/schema/libreoffice/OpenDocument-v1.4+libreoffice-dsig-schema.rng") - + " -O " - + m_directories.getPathFromSrc(u"/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng") - + " -m " - + m_directories.getPathFromSrc(u"/schema/mathml2/mathml2.xsd"); - } - - utl::TempFileNamed aOutput; - aOutput.EnableKillingFile(); - OUString aOutputFile = aOutput.GetFileName(); - OUString aCommand = aValidator + " " + rPath + " > " + aOutputFile + " 2>&1"; - -#if !defined _WIN32 - // For now, this is only needed by some Linux ASan builds, so keep it simply and disable it on - // Windows (which doesn't support the relevant shell syntax for (un-)setting environment - // variables). - OUString env; - if (test::getArgument(u"env", &env)) { - auto const n = env.indexOf('='); - if (n == -1) { - aCommand = "unset -v " + env + " && " + aCommand; - } else { - aCommand = env + " " + aCommand; - } - } -#endif - - SAL_INFO("test", "BootstrapFixture::validate: executing '" << aCommand << "'"); - int returnValue = system(OUStringToOString(aCommand, RTL_TEXTENCODING_UTF8).getStr()); - - OString aContentString = loadFile(aOutput.GetURL()); - OUString aContentOUString = OStringToOUString(aContentString, RTL_TEXTENCODING_UTF8); - - if( eFormat == test::OOXML && !aContentOUString.isEmpty() ) - { - // check for validation errors here - sal_Int32 nIndex = aContentOUString.lastIndexOf(grand_total); - if(nIndex == -1) - { - SAL_WARN("test", "no summary line"); - } - else - { - sal_Int32 nStartOfNumber = nIndex + grand_total.size(); - std::u16string_view aNumber = aContentOUString.subView(nStartOfNumber); - sal_Int32 nErrors = o3tl::toInt32(aNumber); - OString aMsg = "validation error in OOXML export: Errors: " + OString::number(nErrors); - if(nErrors) - { - SAL_WARN("test", aContentOUString); - } - CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), sal_Int32(0), nErrors); - } - } - else if( eFormat == test::ODF && !aContentOUString.isEmpty() ) - { - if( aContentOUString.indexOf("Error") != -1 || aContentOUString.indexOf("Fatal") != -1 ) - { - SAL_WARN("test", aContentOUString); - CPPUNIT_FAIL(aContentString.getStr()); - } - } - CPPUNIT_ASSERT_EQUAL_MESSAGE( - OString( - "failed to execute: " + OUStringToOString(aCommand, RTL_TEXTENCODING_UTF8) + " " - + OUStringToOString(aContentOUString, RTL_TEXTENCODING_UTF8)).getStr(), - 0, returnValue); -#else - (void)rPath; - (void)eFormat; -#endif -} - IMPL_STATIC_LINK( test::BootstrapFixture, ImplInitFilterHdl, ConvertData&, rData, bool) { diff --git a/test/source/unoapi_test.cxx b/test/source/unoapi_test.cxx index be6028aeae66..f97eaa01ba25 100644 --- a/test/source/unoapi_test.cxx +++ b/test/source/unoapi_test.cxx @@ -7,6 +7,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <config_validation.h> + #include <test/unoapi_test.hxx> #include <com/sun/star/beans/NamedValue.hpp> @@ -16,10 +18,13 @@ #include <comphelper/propertyvalue.hxx> #include <comphelper/sequence.hxx> #include <comphelper/sequenceashashmap.hxx> +#include <o3tl/string_view.hxx> #include <osl/file.hxx> +#include <osl/process.h> #include <sfx2/app.hxx> #include <sfx2/objsh.hxx> +#include <unotest/getargument.hxx> #include <unotools/mediadescriptor.hxx> #include <utility> @@ -82,6 +87,171 @@ void UnoApiTest::setTestInteractionHandler(const char* pPassword, rPropertyValue.Value <<= css::uno::Reference<task::XInteractionHandler2>(xInteractionHandler); } +#if HAVE_EXPORT_VALIDATION +namespace +{ +OString loadFile(const OUString& rURL) +{ + osl::File aFile(rURL); + osl::FileBase::RC eStatus = aFile.open(osl_File_OpenFlag_Read); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, eStatus); + sal_uInt64 nSize; + aFile.getSize(nSize); + std::unique_ptr<char[]> aBytes(new char[nSize]); + sal_uInt64 nBytesRead; + aFile.read(aBytes.get(), nSize, nBytesRead); + CPPUNIT_ASSERT_EQUAL(nSize, nBytesRead); + OString aContent(aBytes.get(), nBytesRead); + + return aContent; +} + +constexpr std::u16string_view grand_total = u"Grand total of errors in submitted package: "; +} +#endif + +void UnoApiTest::validate(const OUString& rPath, TestFilter eFilter) const +{ + ValidationFormat eFormat = ValidationFormat::ODF; + if (eFilter == TestFilter::XLSX) + eFormat = ValidationFormat::OOXML; + else if (eFilter == TestFilter::DOCX) + eFormat = ValidationFormat::OOXML; + else if (eFilter == TestFilter::PPTX) + eFormat = ValidationFormat::OOXML; + else if (eFilter == TestFilter::ODT) + eFormat = ValidationFormat::ODF; + else if (eFilter == TestFilter::ODS) + eFormat = ValidationFormat::ODF; + else if (eFilter == TestFilter::ODP) + eFormat = ValidationFormat::ODF; + else if (eFilter == TestFilter::ODG) + eFormat = ValidationFormat::ODF; + else if (eFilter == TestFilter::DOC) + eFormat = ValidationFormat::MSBINARY; + else if (eFilter == TestFilter::XLS) + eFormat = ValidationFormat::MSBINARY; + else if (eFilter == TestFilter::PPT) + eFormat = ValidationFormat::MSBINARY; + else + { + SAL_INFO("test", "UnoApiTest::validate: unknown filter"); + return; + } + +#if HAVE_EXPORT_VALIDATION + OUString var; + if (eFormat == ValidationFormat::OOXML) + { + var = "OFFICEOTRON"; + } + else if (eFormat == ValidationFormat::ODF) + { + var = "ODFVALIDATOR"; + } + else if (eFormat == ValidationFormat::MSBINARY) + { +#if HAVE_BFFVALIDATOR + var = "BFFVALIDATOR"; +#else + // Binary Format Validator is disabled + return; +#endif + } + OUString aValidator; + oslProcessError e = osl_getEnvironment(var.pData, &aValidator.pData); + CPPUNIT_ASSERT_EQUAL_MESSAGE(OUString("cannot get env var " + var).toUtf8().getStr(), + osl_Process_E_None, e); + CPPUNIT_ASSERT_MESSAGE(OUString("empty get env var " + var).toUtf8().getStr(), + !aValidator.isEmpty()); + + if (eFormat == ValidationFormat::ODF) + { + // invoke without -e so that we know when something new is written + // in loext namespace that isn't yet in the custom schema + aValidator + += " -M " + + m_directories.getPathFromSrc( + u"/schema/libreoffice/OpenDocument-v1.4+libreoffice-manifest-schema.rng") + + " -D " + + m_directories.getPathFromSrc( + u"/schema/libreoffice/OpenDocument-v1.4+libreoffice-dsig-schema.rng") + + " -O " + + m_directories.getPathFromSrc( + u"/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng") + + " -m " + m_directories.getPathFromSrc(u"/schema/mathml2/mathml2.xsd"); + } + + utl::TempFileNamed aOutput; + aOutput.EnableKillingFile(); + OUString aOutputFile = aOutput.GetFileName(); + OUString aCommand = aValidator + " " + rPath + " > " + aOutputFile + " 2>&1"; + +#if !defined _WIN32 + // For now, this is only needed by some Linux ASan builds, so keep it simply and disable it on + // Windows (which doesn't support the relevant shell syntax for (un-)setting environment + // variables). + OUString env; + if (test::getArgument(u"env", &env)) + { + auto const n = env.indexOf('='); + if (n == -1) + { + aCommand = "unset -v " + env + " && " + aCommand; + } + else + { + aCommand = env + " " + aCommand; + } + } +#endif + + SAL_INFO("test", "UnoApiTest::validate: executing '" << aCommand << "'"); + int returnValue = system(OUStringToOString(aCommand, RTL_TEXTENCODING_UTF8).getStr()); + + OString aContentString = loadFile(aOutput.GetURL()); + OUString aContentOUString = OStringToOUString(aContentString, RTL_TEXTENCODING_UTF8); + + if (eFormat == ValidationFormat::OOXML && !aContentOUString.isEmpty()) + { + // check for validation errors here + sal_Int32 nIndex = aContentOUString.lastIndexOf(grand_total); + if (nIndex == -1) + { + SAL_WARN("test", "no summary line"); + } + else + { + sal_Int32 nStartOfNumber = nIndex + grand_total.size(); + std::u16string_view aNumber = aContentOUString.subView(nStartOfNumber); + sal_Int32 nErrors = o3tl::toInt32(aNumber); + OString aMsg = "validation error in OOXML export: Errors: " + OString::number(nErrors); + if (nErrors) + { + SAL_WARN("test", aContentOUString); + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), sal_Int32(0), nErrors); + } + } + else if (eFormat == ValidationFormat::ODF && !aContentOUString.isEmpty()) + { + if (aContentOUString.indexOf("Error") != -1 || aContentOUString.indexOf("Fatal") != -1) + { + SAL_WARN("test", aContentOUString); + CPPUNIT_FAIL(aContentString.getStr()); + } + } + CPPUNIT_ASSERT_EQUAL_MESSAGE( + OString("failed to execute: " + OUStringToOString(aCommand, RTL_TEXTENCODING_UTF8) + " " + + OUStringToOString(aContentOUString, RTL_TEXTENCODING_UTF8)) + .getStr(), + 0, returnValue); +#else + (void)rPath; + (void)eFormat; +#endif +} + void UnoApiTest::loadFromURL(OUString const& rURL, const char* pPassword) { std::vector<beans::PropertyValue> aFilterOptions; @@ -187,7 +357,7 @@ void UnoApiTest::save(TestFilter eFilter, const uno::Sequence<beans::PropertyVal xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); if (!mbSkipValidation) - validate(maTempFile.GetFileName(), aFilter); + validate(maTempFile.GetFileName(), eFilter); } void UnoApiTest::saveAndReload(TestFilter eFilter, const char* pPassword)
