LibreOffice Module test (master)  1
bootstrapfixture.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <config_validation.h>
11 
13 #include <vcl/errinf.hxx>
14 #include <sal/log.hxx>
16 
17 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
18 #include <com/sun/star/ucb/XContentProvider.hpp>
19 #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
20 
21 #include <vcl/outdev.hxx>
22 #include <vcl/svapp.hxx>
23 #include <tools/link.hxx>
24 #include <vcl/graphicfilter.hxx>
25 #include <osl/file.hxx>
26 #include <osl/process.h>
27 #include <unotest/getargument.hxx>
28 #include <unotools/tempfile.hxx>
29 #include <vcl/salgtype.hxx>
30 #include <vcl/scheduler.hxx>
31 #include <vcl/virdev.hxx>
32 #include <o3tl/string_view.hxx>
33 
34 #include <memory>
35 #include <cstring>
36 
37 #include "setupvcl.hxx"
38 
39 using namespace ::com::sun::star;
40 
41 static void aBasicErrorFunc( const OUString &rErr, const OUString &rAction )
42 {
43  OString aErr = "Unexpected dialog: " +
44  OUStringToOString( rAction, RTL_TEXTENCODING_ASCII_US ) +
45  " Error: " +
46  OUStringToOString( rErr, RTL_TEXTENCODING_ASCII_US );
47  CPPUNIT_ASSERT_MESSAGE( aErr.getStr(), false);
48 }
49 
50 // NB. this constructor is called before any tests are run, once for each
51 // test function in a rather non-intuitive way. This is why all the 'real'
52 // heavy lifting is deferred until setUp. setUp and tearDown are interleaved
53 // between the tests as you might expect.
54 test::BootstrapFixture::BootstrapFixture( bool bAssertOnDialog, bool bNeedUCB )
55  : m_bNeedUCB( bNeedUCB )
56  , m_bAssertOnDialog( bAssertOnDialog )
57 {
58 }
59 
60 extern "C"
61 {
62 
63 static void test_init_impl(bool bAssertOnDialog, bool bNeedUCB,
64  lang::XMultiServiceFactory * pSFactory)
65 {
66  if (bAssertOnDialog)
68 
69  // Make GraphicConverter work, normally done in desktop::Desktop::Main()
71  LINK(nullptr, test::BootstrapFixture, ImplInitFilterHdl));
72 
73  if (bNeedUCB)
74  {
75  // initialise unconfigured UCB:
76  uno::Reference<ucb::XUniversalContentBroker> xUcb(pSFactory->createInstance("com.sun.star.ucb.UniversalContentBroker"), uno::UNO_QUERY_THROW);
77  uno::Reference<ucb::XContentProvider> xFileProvider(pSFactory->createInstance("com.sun.star.ucb.FileContentProvider"), uno::UNO_QUERY_THROW);
78  xUcb->registerContentProvider(xFileProvider, "file", true);
79  uno::Reference<ucb::XContentProvider> xTdocProvider(pSFactory->createInstance("com.sun.star.ucb.TransientDocumentsContentProvider"), uno::UNO_QUERY);
80  if (xTdocProvider.is())
81  {
82  xUcb->registerContentProvider(xTdocProvider, "vnd.sun.star.tdoc", true);
83  }
84  }
85 }
86 
87 // this is called from pyuno
88 SAL_DLLPUBLIC_EXPORT void test_init(lang::XMultiServiceFactory *pFactory)
89 {
90  try
91  {
92  ::comphelper::setProcessServiceFactory(pFactory);
93  test::setUpVcl(true); // hard-code python tests to headless
94  test_init_impl(false, true, pFactory);
95  }
96  catch (...) { abort(); }
97 }
98 
99 // this is called from pyuno
100 SAL_DLLPUBLIC_EXPORT void test_deinit()
101 {
102  DeInitVCL();
103 }
104 
105 } // extern "C"
106 
108 {
110 
111  test_init_impl(m_bAssertOnDialog, m_bNeedUCB, m_xSFactory.get());
112 
113 #if OSL_DEBUG_LEVEL > 0
115 #endif
116 
117  mxComponentContext.set(comphelper::getComponentContext(getMultiServiceFactory()));
118 }
119 
121 {
122 }
123 
124 #if HAVE_EXPORT_VALIDATION
125 namespace {
126 
127 OString loadFile(const OUString& rURL)
128 {
129  osl::File aFile(rURL);
130  osl::FileBase::RC eStatus = aFile.open(osl_File_OpenFlag_Read);
131  CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, eStatus);
132  sal_uInt64 nSize;
133  aFile.getSize(nSize);
134  std::unique_ptr<char[]> aBytes(new char[nSize]);
135  sal_uInt64 nBytesRead;
136  aFile.read(aBytes.get(), nSize, nBytesRead);
137  CPPUNIT_ASSERT_EQUAL(nSize, nBytesRead);
138  OString aContent(aBytes.get(), nBytesRead);
139 
140  return aContent;
141 }
142 
143 }
144 #endif
145 
146 void test::BootstrapFixture::validate(const OUString& rPath, test::ValidationFormat eFormat) const
147 {
148 #if HAVE_EXPORT_VALIDATION
149  OUString var;
150  if( eFormat == test::OOXML )
151  {
152  var = "OFFICEOTRON";
153  }
154  else if ( eFormat == test::ODF )
155  {
156  var = "ODFVALIDATOR";
157  }
158  else if ( eFormat == test::MSBINARY )
159  {
160 #if HAVE_BFFVALIDATOR
161  var = "BFFVALIDATOR";
162 #else
163  // Binary Format Validator is disabled
164  return;
165 #endif
166  }
167  OUString aValidator;
168  oslProcessError e = osl_getEnvironment(var.pData, &aValidator.pData);
169  CPPUNIT_ASSERT_EQUAL_MESSAGE(
170  OUString("cannot get env var " + var).toUtf8().getStr(),
171  osl_Process_E_None, e);
172  CPPUNIT_ASSERT_MESSAGE(
173  OUString("empty get env var " + var).toUtf8().getStr(),
174  !aValidator.isEmpty());
175 
176  if (eFormat == test::ODF)
177  {
178  // invoke without -e so that we know when something new is written
179  // in loext namespace that isn't yet in the custom schema
180  aValidator += " -M "
181  + m_directories.getPathFromSrc(u"/schema/libreoffice/OpenDocument-v1.3+libreoffice-manifest-schema.rng")
182  + " -D "
183  + m_directories.getPathFromSrc(u"/schema/libreoffice/OpenDocument-v1.3+libreoffice-dsig-schema.rng")
184  + " -O "
185  + m_directories.getPathFromSrc(u"/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng")
186  + " -m "
187  + m_directories.getPathFromSrc(u"/schema/mathml2/mathml2.xsd");
188  }
189 
190  utl::TempFile aOutput;
191  aOutput.EnableKillingFile();
192  OUString aOutputFile = aOutput.GetFileName();
193  OUString aCommand = aValidator + " " + rPath + " > " + aOutputFile + " 2>&1";
194 
195 #if !defined _WIN32
196  // For now, this is only needed by some Linux ASan builds, so keep it simply and disable it on
197  // Windows (which doesn't support the relevant shell syntax for (un-)setting environment
198  // variables).
199  OUString env;
200  if (test::getArgument(u"env", &env)) {
201  auto const n = env.indexOf('=');
202  if (n == -1) {
203  aCommand = "unset -v " + env + " && " + aCommand;
204  } else {
205  aCommand = env + " " + aCommand;
206  }
207  }
208 #endif
209 
210  SAL_INFO("test", "BootstrapFixture::validate: executing '" << aCommand << "'");
211  int returnValue = system(OUStringToOString(aCommand, RTL_TEXTENCODING_UTF8).getStr());
212 
213  OString aContentString = loadFile(aOutput.GetURL());
214  OUString aContentOUString = OStringToOUString(aContentString, RTL_TEXTENCODING_UTF8);
215 
216  if( eFormat == test::OOXML && !aContentOUString.isEmpty() )
217  {
218  // check for validation errors here
219  sal_Int32 nIndex = aContentOUString.lastIndexOf("Grand total of errors in submitted package: ");
220  if(nIndex == -1)
221  {
222  SAL_WARN("test", "no summary line");
223  }
224  else
225  {
226  sal_Int32 nStartOfNumber = nIndex + std::strlen("Grand total of errors in submitted package: ");
227  std::u16string_view aNumber = aContentOUString.subView(nStartOfNumber);
228  sal_Int32 nErrors = o3tl::toInt32(aNumber);
229  OString aMsg = "validation error in OOXML export: Errors: " + OString::number(nErrors);
230  if(nErrors)
231  {
232  SAL_WARN("test", aContentOUString);
233  }
234  CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), sal_Int32(0), nErrors);
235  }
236  }
237  else if( eFormat == test::ODF && !aContentOUString.isEmpty() )
238  {
239  if( aContentOUString.indexOf("Error") != -1 )
240  {
241  SAL_WARN("test", aContentOUString);
242  CPPUNIT_FAIL(aContentString.getStr());
243  }
244  }
245  CPPUNIT_ASSERT_EQUAL_MESSAGE(
246  OString(
247  "failed to execute: " + OUStringToOString(aCommand, RTL_TEXTENCODING_UTF8) + "\n"
248  + OUStringToOString(aContentOUString, RTL_TEXTENCODING_UTF8)).getStr(),
249  0, returnValue);
250 #else
251  (void)rPath;
252  (void)eFormat;
253 #endif
254 }
255 
257  test::BootstrapFixture, ImplInitFilterHdl, ConvertData&, rData, bool)
258 {
260 }
261 
263 {
264  return (Application::GetDefaultDevice()->GetDPIX() == 96
265  && Application::GetDefaultDevice()->GetDPIY() == 96);
266 }
267 
268 std::pair<double, double> test::BootstrapFixture::getDPIScaling()
269 {
270  return { Application::GetDefaultDevice()->GetDPIX() / 96.0,
272 }
273 
275 {
277  = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
278  return device->GetBitCount();
279 }
280 
281 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static sal_uInt16 getDefaultDeviceBitCount()
static void test_init_impl(bool bAssertOnDialog, bool bNeedUCB, lang::XMultiServiceFactory *pSFactory)
sal_Int32 nIndex
sal_Int64 n
const ContentProperties & rData
exports com.sun.star. system
OOO_DLLPUBLIC_TEST_SETUPVCL void setUpVcl(bool forceHeadless=false)
Definition: setupvcl.cxx:73
SAL_DLLPUBLIC_EXPORT void test_deinit()
static OutputDevice * GetDefaultDevice()
bool getArgument(std::u16string_view name, OUString *value)
static void SetFilterHdl(const Link< ConvertData &, bool > &rLink)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
static std::pair< double, double > getDPIScaling()
css::uno::Reference< css::uno::XComponentContext > mxComponentContext
OUString const & GetURL() const
float u
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
SAL_DLLPUBLIC_EXPORT void test_init(lang::XMultiServiceFactory *pFactory)
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
Link< ConvertData &, bool > GetFilterCallback() const
static void aBasicErrorFunc(const OUString &rErr, const OUString &rAction)
virtual void setUp() override
void validate(const OUString &rURL, ValidationFormat) const
virtual void setUp() override
OUString GetFileName() const
#define SAL_INFO(area, stream)
static VclPtr< reference_type > Create(Arg &&...arg)
static void ProcessEventsToIdle()
static void RegisterDisplay(BasicDisplayErrorFunc *)
static GraphicFilter & GetGraphicFilter()
#define SAL_WARN(area, stream)
OUString aCommand
IMPL_STATIC_LINK(test::BootstrapFixture, ImplInitFilterHdl, ConvertData &, rData, bool)
VCL_DLLPUBLIC void DeInitVCL()
SAL_DLLPRIVATE sal_Int32 GetDPIY() const
BootstrapFixture(bool bAssertOnDialog=true, bool bNeedUCB=true)
void EnableKillingFile(bool bEnable=true)
SAL_DLLPRIVATE sal_Int32 GetDPIX() const
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo
virtual ~BootstrapFixture() override