From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- .../complex/ModuleManager/CheckXModuleManager.java | 330 ++++++++ framework/qa/complex/XTitle/CheckXTitle.java | 325 ++++++++ .../AcceleratorsConfigurationTest.java | 789 ++++++++++++++++++ framework/qa/complex/accelerators/KeyMapping.java | 143 ++++ framework/qa/complex/api_internal/CheckAPI.java | 180 +++++ framework/qa/complex/api_internal/api.lst | 263 ++++++ framework/qa/complex/api_internal/tests.sce | 2 + framework/qa/complex/api_internal/worksforme.sce | 54 ++ .../qa/complex/broken_document/LoadDocument.java | 108 +++ .../qa/complex/broken_document/TestDocument.java | 33 + .../broken_document/test_documents/dbf.dbf.emf | 1 + .../CheckContextMenuInterceptor.java | 304 +++++++ .../ContextMenuInterceptor.java | 132 +++ .../complex/contextMenuInterceptor/space-metal.jpg | Bin 0 -> 4313 bytes framework/qa/complex/desktop/DesktopTerminate.java | 144 ++++ framework/qa/complex/dispatches/Interceptor.java | 338 ++++++++ .../qa/complex/dispatches/checkdispatchapi.java | 401 ++++++++++ .../disposing/GetServiceWhileDisposingOffice.java | 82 ++ .../qa/complex/framework/autosave/AutoSave.java | 451 +++++++++++ .../complex/framework/autosave/ConfigHelper.java | 94 +++ .../qa/complex/framework/autosave/Protocol.java | 890 +++++++++++++++++++++ .../qa/complex/framework/recovery/CrashThread.java | 72 ++ .../framework/recovery/KlickButtonThread.java | 46 ++ .../complex/framework/recovery/RecoveryTest.java | 611 ++++++++++++++ .../complex/framework/recovery/RecoveryTools.java | 301 +++++++ .../qa/complex/imageManager/CheckImageManager.java | 201 +++++ framework/qa/complex/imageManager/_XComponent.java | 167 ++++ .../qa/complex/imageManager/_XImageManager.java | 105 +++ .../qa/complex/imageManager/_XInitialization.java | 78 ++ .../qa/complex/imageManager/_XTypeProvider.java | 89 +++ .../qa/complex/imageManager/_XUIConfiguration.java | 66 ++ .../imageManager/_XUIConfigurationPersistence.java | 84 ++ .../loadAllDocuments/CheckXComponentLoader.java | 526 ++++++++++++ .../loadAllDocuments/CheckXComponentLoader.props | 1 + .../loadAllDocuments/InteractionHandler.java | 122 +++ .../complex/loadAllDocuments/StatusIndicator.java | 145 ++++ .../loadAllDocuments/testdocuments/Calc_6.sxc | Bin 0 -> 9547 bytes .../loadAllDocuments/testdocuments/Writer6.sxw | Bin 0 -> 5754 bytes .../loadAllDocuments/testdocuments/draw1.sxd | Bin 0 -> 11821 bytes .../loadAllDocuments/testdocuments/imp1.sxi | Bin 0 -> 35135 bytes .../testdocuments/password_check.sxw | Bin 0 -> 5128 bytes .../complex/loadAllDocuments/testdocuments/pic.gif | Bin 0 -> 1433 bytes .../complex/loadAllDocuments/testdocuments/pic.jpg | Bin 0 -> 2651 bytes .../qa/complex/path_settings/PathSettingsTest.java | 721 +++++++++++++++++ .../path_substitution/PathSubstitutionTest.java | 294 +++++++ framework/qa/cppunit/data/double-loading.odt | Bin 0 -> 13729 bytes framework/qa/cppunit/data/empty.fodp | 2 + framework/qa/cppunit/dispatchtest.cxx | 219 +++++ framework/qa/cppunit/loadenv.cxx | 86 ++ framework/qa/cppunit/services.cxx | 157 ++++ framework/qa/unoapi/framework.sce | 51 ++ framework/qa/unoapi/knownissues.xcl | 77 ++ framework/qa/unoapi/testdocuments/Calc_Link.sxc | Bin 0 -> 5410 bytes framework/qa/unoapi/testdocuments/Writer_link.sxw | Bin 0 -> 5188 bytes .../qa/unoapi/testdocuments/XTypeDetection.sxw | Bin 0 -> 4995 bytes framework/qa/unoapi/testdocuments/delete.cfg | Bin 0 -> 2799 bytes 56 files changed, 9285 insertions(+) create mode 100644 framework/qa/complex/ModuleManager/CheckXModuleManager.java create mode 100644 framework/qa/complex/XTitle/CheckXTitle.java create mode 100644 framework/qa/complex/accelerators/AcceleratorsConfigurationTest.java create mode 100644 framework/qa/complex/accelerators/KeyMapping.java create mode 100644 framework/qa/complex/api_internal/CheckAPI.java create mode 100644 framework/qa/complex/api_internal/api.lst create mode 100644 framework/qa/complex/api_internal/tests.sce create mode 100644 framework/qa/complex/api_internal/worksforme.sce create mode 100644 framework/qa/complex/broken_document/LoadDocument.java create mode 100644 framework/qa/complex/broken_document/TestDocument.java create mode 100644 framework/qa/complex/broken_document/test_documents/dbf.dbf.emf create mode 100644 framework/qa/complex/contextMenuInterceptor/CheckContextMenuInterceptor.java create mode 100644 framework/qa/complex/contextMenuInterceptor/ContextMenuInterceptor.java create mode 100644 framework/qa/complex/contextMenuInterceptor/space-metal.jpg create mode 100644 framework/qa/complex/desktop/DesktopTerminate.java create mode 100644 framework/qa/complex/dispatches/Interceptor.java create mode 100644 framework/qa/complex/dispatches/checkdispatchapi.java create mode 100644 framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java create mode 100644 framework/qa/complex/framework/autosave/AutoSave.java create mode 100644 framework/qa/complex/framework/autosave/ConfigHelper.java create mode 100644 framework/qa/complex/framework/autosave/Protocol.java create mode 100644 framework/qa/complex/framework/recovery/CrashThread.java create mode 100644 framework/qa/complex/framework/recovery/KlickButtonThread.java create mode 100644 framework/qa/complex/framework/recovery/RecoveryTest.java create mode 100644 framework/qa/complex/framework/recovery/RecoveryTools.java create mode 100644 framework/qa/complex/imageManager/CheckImageManager.java create mode 100644 framework/qa/complex/imageManager/_XComponent.java create mode 100644 framework/qa/complex/imageManager/_XImageManager.java create mode 100644 framework/qa/complex/imageManager/_XInitialization.java create mode 100644 framework/qa/complex/imageManager/_XTypeProvider.java create mode 100644 framework/qa/complex/imageManager/_XUIConfiguration.java create mode 100644 framework/qa/complex/imageManager/_XUIConfigurationPersistence.java create mode 100644 framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java create mode 100644 framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props create mode 100644 framework/qa/complex/loadAllDocuments/InteractionHandler.java create mode 100644 framework/qa/complex/loadAllDocuments/StatusIndicator.java create mode 100644 framework/qa/complex/loadAllDocuments/testdocuments/Calc_6.sxc create mode 100644 framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxw create mode 100644 framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxd create mode 100644 framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxi create mode 100644 framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxw create mode 100644 framework/qa/complex/loadAllDocuments/testdocuments/pic.gif create mode 100644 framework/qa/complex/loadAllDocuments/testdocuments/pic.jpg create mode 100644 framework/qa/complex/path_settings/PathSettingsTest.java create mode 100644 framework/qa/complex/path_substitution/PathSubstitutionTest.java create mode 100644 framework/qa/cppunit/data/double-loading.odt create mode 100644 framework/qa/cppunit/data/empty.fodp create mode 100644 framework/qa/cppunit/dispatchtest.cxx create mode 100644 framework/qa/cppunit/loadenv.cxx create mode 100644 framework/qa/cppunit/services.cxx create mode 100644 framework/qa/unoapi/framework.sce create mode 100644 framework/qa/unoapi/knownissues.xcl create mode 100644 framework/qa/unoapi/testdocuments/Calc_Link.sxc create mode 100644 framework/qa/unoapi/testdocuments/Writer_link.sxw create mode 100644 framework/qa/unoapi/testdocuments/XTypeDetection.sxw create mode 100644 framework/qa/unoapi/testdocuments/delete.cfg (limited to 'framework/qa') diff --git a/framework/qa/complex/ModuleManager/CheckXModuleManager.java b/framework/qa/complex/ModuleManager/CheckXModuleManager.java new file mode 100644 index 000000000..1015d00c2 --- /dev/null +++ b/framework/qa/complex/ModuleManager/CheckXModuleManager.java @@ -0,0 +1,330 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.ModuleManager; + +import com.sun.star.beans.*; +import com.sun.star.frame.*; +import com.sun.star.lang.*; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.*; +import com.sun.star.container.*; + + + +// ---------- junit imports ----------------- +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; +import static org.junit.Assert.*; + + + +/** @short todo document me + */ +public class CheckXModuleManager +{ + + // some const + + + // member + + /** points to the global uno service manager. */ + private XMultiServiceFactory m_xSmgr = null; + + /** the module manager for testing. */ + private XModuleManager m_xMM = null; + + /** a special frame used to load documents there. */ + private XComponentLoader m_xLoader = null; + + + // test environment + + + /** @short Create the environment for following tests. + + @descr Use either a component loader from desktop or + from frame + */ + @Before public void before() + throws java.lang.Exception + { + // get uno service manager from global test environment + m_xSmgr = getMSF(); + + // create module manager + m_xMM = UnoRuntime.queryInterface(XModuleManager.class, m_xSmgr.createInstance("com.sun.star.frame.ModuleManager")); + + // create desktop instance to create a special frame to load documents there. + XFrame xDesktop = UnoRuntime.queryInterface(XFrame.class, m_xSmgr.createInstance("com.sun.star.frame.Desktop")); + + m_xLoader = UnoRuntime.queryInterface(XComponentLoader.class, xDesktop.findFrame("_blank", 0)); + } + + + /** @short close the environment. + */ + @After public void after() + throws java.lang.Exception + { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, m_xLoader); + xClose.close(false); + + m_xLoader = null; + m_xMM = null; + m_xSmgr = null; + } + + + /** @todo document me + */ + @Test public void checkModuleIdentification() + throws java.lang.Exception + { + impl_identifyModulesBasedOnDocs("com.sun.star.text.TextDocument" ); + impl_identifyModulesBasedOnDocs("com.sun.star.text.WebDocument" ); + impl_identifyModulesBasedOnDocs("com.sun.star.text.GlobalDocument" ); + impl_identifyModulesBasedOnDocs("com.sun.star.formula.FormulaProperties" ); + impl_identifyModulesBasedOnDocs("com.sun.star.sheet.SpreadsheetDocument" ); + impl_identifyModulesBasedOnDocs("com.sun.star.drawing.DrawingDocument" ); + impl_identifyModulesBasedOnDocs("com.sun.star.presentation.PresentationDocument"); + impl_identifyModulesBasedOnDocs("com.sun.star.sdb.OfficeDatabaseDocument" ); + // TODO: fails + // impl_identifyModulesBasedOnDocs("com.sun.star.chart.ChartDocument" ); + } + + + /** @todo document me + */ + @Test public void checkModuleConfigurationReadable() + throws java.lang.Exception + { + } + + + /** @todo document me + */ + @Test public void checkModuleConfigurationWriteable() + throws java.lang.Exception + { + // modules supporting real documents + impl_checkReadOnlyPropsOfModule("com.sun.star.text.TextDocument" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.text.WebDocument" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.text.GlobalDocument" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.formula.FormulaProperties" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.sheet.SpreadsheetDocument" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.drawing.DrawingDocument" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.presentation.PresentationDocument"); + impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.OfficeDatabaseDocument" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.chart.ChartDocument" ); + + // other modules + impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.FormDesign" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.TextReportDesign" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.RelationDesign" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.QueryDesign" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.TableDesign" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.DataSourceBrowser"); + impl_checkReadOnlyPropsOfModule("com.sun.star.frame.Bibliography" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.script.BasicIDE" ); + impl_checkReadOnlyPropsOfModule("com.sun.star.frame.StartModule" ); + } + + + /** @todo document me + */ + @Test public void checkModuleConfigurationQueries() + throws java.lang.Exception + { + impl_searchModulesByDocumentService("com.sun.star.text.TextDocument" ); + impl_searchModulesByDocumentService("com.sun.star.text.WebDocument" ); + impl_searchModulesByDocumentService("com.sun.star.text.GlobalDocument" ); + impl_searchModulesByDocumentService("com.sun.star.formula.FormulaProperties" ); + impl_searchModulesByDocumentService("com.sun.star.sheet.SpreadsheetDocument" ); + impl_searchModulesByDocumentService("com.sun.star.drawing.DrawingDocument" ); + impl_searchModulesByDocumentService("com.sun.star.presentation.PresentationDocument"); + impl_searchModulesByDocumentService("com.sun.star.sdb.OfficeDatabaseDocument" ); + impl_searchModulesByDocumentService("com.sun.star.chart.ChartDocument" ); + } + + + /** @todo document me + */ + private void impl_searchModulesByDocumentService(String sDocumentService) + throws java.lang.Exception + { + System.out.println("search modules matching document service '"+sDocumentService+"' ..."); + + NamedValue[] lProps = new NamedValue[1]; + lProps[0] = new NamedValue(); + lProps[0].Name = "ooSetupFactoryDocumentService"; + lProps[0].Value = sDocumentService; + + XContainerQuery xMM = UnoRuntime.queryInterface(XContainerQuery.class, m_xMM); + XEnumeration xResult = xMM.createSubSetEnumerationByProperties(lProps); + while(xResult.hasMoreElements()) + { + PropertyValue[] lModuleProps = (PropertyValue[])AnyConverter.toArray(xResult.nextElement()); + int c = lModuleProps.length; + int i = 0; + String sFoundModule = ""; + String sFoundDocService = ""; + for (i=0; i 0) + { + System.out.println("** get command by " + sKeys[i] + " **"); + + String sCmdFromCache = ""; // get a value using XAcceleratorConfiguration API + String sCmdFromConfiguration = ""; // get a value using configuration API + + // GET shortcuts/commands using XAcceleratorConfiguration API + sCmdFromCache = xAccelCfg.getCommandByKeyEvent(convertShortcut2AWTKey(sKeys[i])); + System.out.println(sKeys[i] + "-->" + sCmdFromCache + ", by XAcceleratorConfiguration API"); + + // GET shortcuts/commands using configuration API + sCmdFromConfiguration = getCommandFromConfiguration(xAccess, sKeys[i]); + System.out.println(sKeys[i] + "-->" + sCmdFromConfiguration + ", by configuration API"); + + assertTrue("values are different by XAcceleratorConfiguration API and configuration API!", sCmdFromCache.equals(sCmdFromConfiguration)); + + String sLocale = "es"; + setOfficeLocale(sLocale); + sCmdFromConfiguration = getCommandFromConfiguration(xAccess, sKeys[i]); + System.out.println(sKeys[i] + "-->" + sCmdFromConfiguration + ", by configuration API" + " for locale:" + getOfficeLocale()); + + sLocale = "en-US"; + setOfficeLocale(sLocale); //reset to default locale + } + else + { + System.out.println(sKeys[i] + " doesn't exist!"); + } + } + } + + + /** @todo document me. + */ + private void impl_checkSetKeyCommands(XAcceleratorConfiguration xAccelCfg, XNameAccess xPrimaryAccess, XNameAccess xSecondaryAccess, String[] sKeys, String[] sCommands) + throws java.lang.Exception + { + System.out.println("check setKeyCommands..."); + + for (int i = 0; i < sKeys.length; ++i) + { + if (!xPrimaryAccess.hasByName(sKeys[i]) && !xSecondaryAccess.hasByName(sKeys[i])) + { + xAccelCfg.setKeyEvent(convertShortcut2AWTKey(sKeys[i]), sCommands[i]); + xAccelCfg.store(); + if (xPrimaryAccess.hasByName(sKeys[i])) + { + System.out.println("add " + sKeys[i] + " successfully!"); + } + else + { + System.out.println("add " + sKeys[i] + " failed!"); + } + } + else if (xPrimaryAccess.hasByName(sKeys[i])) + { + String sOriginalCommand = getCommandFromConfiguration(xPrimaryAccess, sKeys[i]); + if (!sCommands[i].equals(sOriginalCommand)) + { + xAccelCfg.setKeyEvent(convertShortcut2AWTKey(sKeys[i]), sCommands[i]); + xAccelCfg.store(); + + String sChangedCommand = getCommandFromConfiguration(xPrimaryAccess, sKeys[i]); + if (sCommands[i].equals(sChangedCommand)) + { + System.out.println("change " + sKeys[i] + " successfully!"); + } + else + { + System.out.println("change " + sKeys[i] + " failed!"); + } + } + else + { + System.out.println(sKeys[i] + " already exist!"); + } + } + else if (xSecondaryAccess.hasByName(sKeys[i])) + { + String sOriginalCommand = getCommandFromConfiguration(xSecondaryAccess, sKeys[i]); + if (!sCommands[i].equals(sOriginalCommand)) + { + xAccelCfg.setKeyEvent(convertShortcut2AWTKey(sKeys[i]), sCommands[i]); + xAccelCfg.store(); + + String sChangedCommand = getCommandFromConfiguration(xPrimaryAccess, sKeys[i]); + if (sCommands[i].equals(sChangedCommand)) + { + System.out.println("change " + sKeys[i] + " successfully!"); + } + else + { + System.out.println("change " + sKeys[i] + " failed!"); + } + } + else + { + System.out.println(sKeys[i] + " already exist!"); + } + } + } + } + + + /** @todo document me. + */ + private void impl_checkRemoveKeyCommands(XAcceleratorConfiguration xAccelCfg, XNameAccess xPrimaryAccess, XNameAccess xSecondaryAccess, String[] sKeys) + throws java.lang.Exception + { + System.out.println("check removeKeyCommands..."); + + for (int i = 0; i < sKeys.length; i++) + { + if (!xPrimaryAccess.hasByName(sKeys[i]) && !xSecondaryAccess.hasByName(sKeys[i])) + { + System.out.println(sKeys[i] + " doesn't exist!"); + } + else if (xPrimaryAccess.hasByName(sKeys[i])) + { + xAccelCfg.removeKeyEvent(convertShortcut2AWTKey(sKeys[i])); + xAccelCfg.store(); + if (!xPrimaryAccess.hasByName(sKeys[i])) + { + System.out.println("Remove " + sKeys[i] + " successfully!"); + } + else + { + System.out.println("Remove " + sKeys[i] + " failed!"); + } + } + else if (xSecondaryAccess.hasByName(sKeys[i])) + { + xAccelCfg.removeKeyEvent(convertShortcut2AWTKey(sKeys[i])); + xAccelCfg.store(); + if (!xSecondaryAccess.hasByName(sKeys[i])) + { + System.out.println("Remove " + sKeys[i] + " successfully!"); + } + else + { + System.out.println("Remove " + sKeys[i] + " failed!"); + } + } + } + } + + + /** @todo document me. + */ + private void impl_checkGetPreferredKeyEventsForCommandList(XAcceleratorConfiguration xAccelCfg, XNameAccess xPrimaryAccess, String[] sCommandList) + throws java.lang.Exception + { + System.out.println("check getPreferredKeyEventsForCommandList..."); + + Object[] oKeyEvents = xAccelCfg.getPreferredKeyEventsForCommandList(sCommandList); + for (int i = 0; i < oKeyEvents.length; i++) + { + System.out.println("get preferred key for command " + sCommandList[i] + ":"); + + KeyEvent aKeyEvent = (KeyEvent) AnyConverter.toObject(KeyEvent.class, oKeyEvents[i]); + String sKeyEvent = convertAWTKey2Shortcut(aKeyEvent); + System.out.println(sKeyEvent); + + String sCmdFromConfiguration = getCommandFromConfiguration(xPrimaryAccess, sKeyEvent); + System.out.println(sCmdFromConfiguration); + if (sCommandList[i].equals(sCmdFromConfiguration)) + { + System.out.println("get preferred key correctly!"); + } + else + { + System.out.println("get preferred key failed!"); + } + } + } + + + /** @todo document me. + */ + private String getCommandFromConfiguration(XNameAccess xAccess, String sKey) + throws java.lang.Exception + { + String sCommand = ""; + + if (xAccess.hasByName(sKey)) + { + XNameAccess xKey = UnoRuntime.queryInterface(XNameAccess.class, xAccess.getByName(sKey)); + XNameAccess xCommand = UnoRuntime.queryInterface(XNameAccess.class, xKey.getByName("Command")); + + String sLocale = getOfficeLocale(); + if (xCommand.hasByName(sLocale)) + { + sCommand = UnoRuntime.queryInterface(String.class, xCommand.getByName(sLocale)); + } + } + + return sCommand; + } + + + /** @todo document me. + */ + private void LoadDocumentAcceleratorConfiguration(String sDocCfgName) + throws java.lang.Exception + { + XSingleServiceFactory xStorageFactory = UnoRuntime.queryInterface(XSingleServiceFactory.class, m_xSmgr.createInstance("com.sun.star.embed.StorageFactory")); + + Object aArgs[] = new Object[2]; + aArgs[0] = sDocCfgName; + aArgs[1] = Integer.valueOf(com.sun.star.embed.ElementModes.READ); + XStorage xRootStorage = UnoRuntime.queryInterface(XStorage.class, xStorageFactory.createInstanceWithArguments(aArgs)); + + XStorage xUIConfig = xRootStorage.openStorageElement("Configurations2", com.sun.star.embed.ElementModes.READ); + + PropertyValue aProp = new PropertyValue(); + aProp.Name = "DocumentRoot"; + aProp.Value = xUIConfig; + Object[] lArgs = new Object[1]; + lArgs[0] = aProp; + + XInitialization xInit = UnoRuntime.queryInterface(XInitialization.class, m_xDocumentAccelCfg); + xInit.initialize(lArgs); + + // TODO: throws css::container::NoSuchElementException + try + { + String test = m_xDocumentAccelCfg.getCommandByKeyEvent(convertShortcut2AWTKey("F2")); + System.out.println(test); + } + catch(com.sun.star.container.NoSuchElementException e) + { + System.out.println("NoSuchElementException caught: " + e.getMessage()); + } + } + + + /** @todo document me. + */ + private void SaveDocumentAcceleratorConfiguration(String sDocCfgName) + throws java.lang.Exception + { + XSingleServiceFactory xStorageFactory = UnoRuntime.queryInterface(XSingleServiceFactory.class, m_xSmgr.createInstance("com.sun.star.embed.StorageFactory")); + + Object aArgs[] = new Object[2]; + aArgs[0] = sDocCfgName; + aArgs[1] = Integer.valueOf(com.sun.star.embed.ElementModes.WRITE); + XStorage xRootStorage = UnoRuntime.queryInterface(XStorage.class, xStorageFactory.createInstanceWithArguments(aArgs)); + + XStorage xUIConfig = xRootStorage.openStorageElement("Configurations2", com.sun.star.embed.ElementModes.WRITE); + + XUIConfigurationManager xCfgMgr = UnoRuntime.queryInterface(XUIConfigurationManager.class, m_xSmgr.createInstance("com.sun.star.ui.UIConfigurationManager")); + + XUIConfigurationStorage xUICfgStore = UnoRuntime.queryInterface(XUIConfigurationStorage.class, xCfgMgr); + xUICfgStore.setStorage(xUIConfig); + + XPropertySet xUIConfigProps = UnoRuntime.queryInterface(XPropertySet.class, xUIConfig); + xUIConfigProps.setPropertyValue("MediaType", "application/vnd.sun.xml.ui.configuration"); + + if (xCfgMgr != null) + { + XAcceleratorConfiguration xTargetAccMgr = UnoRuntime.queryInterface(XAcceleratorConfiguration.class, xCfgMgr.getShortCutManager()); + XUIConfigurationPersistence xCommit1 = UnoRuntime.queryInterface(XUIConfigurationPersistence.class, xTargetAccMgr); + XUIConfigurationPersistence xCommit2 = UnoRuntime.queryInterface(XUIConfigurationPersistence.class, xCfgMgr); + xCommit1.store(); + xCommit2.store(); + + XTransactedObject xCommit3 = UnoRuntime.queryInterface(XTransactedObject.class, xRootStorage); + xCommit3.commit(); + } + } + + + /** @todo document me. + */ + private com.sun.star.awt.KeyEvent convertShortcut2AWTKey(String sShortcut) + throws java.lang.Exception + { + com.sun.star.awt.KeyEvent aKeyEvent = new com.sun.star.awt.KeyEvent(); + KeyMapping aKeyMapping = new KeyMapping(); + String[] sShortcutSplits = sShortcut.split("_"); + + aKeyEvent.KeyCode = aKeyMapping.mapIdentifier2Code(sShortcutSplits[0]); + for (int i = 1; i < sShortcutSplits.length; i++) + { + if (sShortcutSplits[i].equals("SHIFT")) + { + aKeyEvent.Modifiers |= com.sun.star.awt.KeyModifier.SHIFT; + } + else if (sShortcutSplits[i].equals("MOD1")) + { + aKeyEvent.Modifiers |= com.sun.star.awt.KeyModifier.MOD1; + } + else if (sShortcutSplits[i].equals("MOD2")) + { + aKeyEvent.Modifiers |= com.sun.star.awt.KeyModifier.MOD2; + } + } + + return aKeyEvent; + } + + + /** @todo document me. + */ + private String convertAWTKey2Shortcut(com.sun.star.awt.KeyEvent aKeyEvent) + throws java.lang.Exception + { + String sShortcut; + + KeyMapping aKeyMapping = new KeyMapping(); + sShortcut = aKeyMapping.mapCode2Identifier(aKeyEvent.KeyCode); + + if ((aKeyEvent.Modifiers & com.sun.star.awt.KeyModifier.SHIFT) == com.sun.star.awt.KeyModifier.SHIFT) + { + sShortcut += "_SHIFT"; + } + if ((aKeyEvent.Modifiers & com.sun.star.awt.KeyModifier.MOD1) == com.sun.star.awt.KeyModifier.MOD1) + { + sShortcut += "_MOD1"; + } + if ((aKeyEvent.Modifiers & com.sun.star.awt.KeyModifier.MOD2) == com.sun.star.awt.KeyModifier.MOD2) + { + sShortcut += "_MOD2"; + } + + return sShortcut; + } + + + /** @todo document me. + */ + private String getOfficeLocale() + throws java.lang.Exception + { + String sLocale = ""; + + String sConfigPath = "org.openoffice.Setup"; + boolean bReadOnly = true; + XNameAccess xRootConfig = openConfig(sConfigPath, bReadOnly); + + if (xRootConfig != null) + { + XNameAccess xLocale = UnoRuntime.queryInterface(XNameAccess.class, xRootConfig.getByName("L10N")); + XPropertySet xSet = UnoRuntime.queryInterface(XPropertySet.class, xLocale); + sLocale = (String) xSet.getPropertyValue("ooLocale"); + } + + return sLocale; + } + + + /** @todo document me. + */ + private void setOfficeLocale(String sLocale) + throws java.lang.Exception + { + String sConfigPath = "org.openoffice.Setup"; + boolean bReadOnly = false; + XNameAccess xRootConfig = openConfig(sConfigPath, bReadOnly); + + if (xRootConfig != null) + { + XNameAccess xLocale = UnoRuntime.queryInterface(XNameAccess.class, xRootConfig.getByName("L10N")); + XPropertySet xSet = UnoRuntime.queryInterface(XPropertySet.class, xLocale); + xSet.setPropertyValue("ooLocale", sLocale); + XChangesBatch xBatch = UnoRuntime.queryInterface(XChangesBatch.class, xRootConfig); + xBatch.commitChanges(); + } + } + + + /** @todo document me. + */ + private XNameAccess openConfig( + String sConfigPath, + boolean bReadOnly) + throws java.lang.Exception + { + XMultiServiceFactory xConfigRoot = theDefaultProvider.get( + connection.getComponentContext()); + + PropertyValue[] lParams = new PropertyValue[2]; + lParams[0] = new PropertyValue(); + lParams[0].Name = "nodepath"; + lParams[0].Value = sConfigPath; + + lParams[1] = new PropertyValue(); + lParams[1].Name = "locale"; + lParams[1].Value = "*"; + + Object aConfig; + if (bReadOnly) + { + aConfig = xConfigRoot.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", lParams); + } + else + { + aConfig = xConfigRoot.createInstanceWithArguments("com.sun.star.configuration.ConfigurationUpdateAccess", lParams); + } + + XNameAccess xConfig = UnoRuntime.queryInterface(XNameAccess.class, aConfig); + + if (xConfig == null) + { + throw new com.sun.star.uno.Exception("Could not open configuration \"" + sConfigPath + "\""); + } + + return xConfig; + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + private static final OfficeConnection connection = new OfficeConnection(); +} diff --git a/framework/qa/complex/accelerators/KeyMapping.java b/framework/qa/complex/accelerators/KeyMapping.java new file mode 100644 index 000000000..fd3637ba2 --- /dev/null +++ b/framework/qa/complex/accelerators/KeyMapping.java @@ -0,0 +1,143 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.accelerators; + +import java.util.HashMap; + +class KeyIdentifierInfo +{ + protected String sIdentifier; + protected Short nCode; + + KeyIdentifierInfo(String sID, Short nC) + { + sIdentifier = sID; + nCode = nC; + } +} + +class IdentifierHashMap extends HashMap +{ +} + +class CodeHashMap extends HashMap +{ +} + +public class KeyMapping +{ + private final IdentifierHashMap aIdentifierHashMap; + private final CodeHashMap aCodeHashMap; + + public KeyMapping() + { + KeyIdentifierInfo[] aInfoMap = { + new KeyIdentifierInfo("0", Short.valueOf(com.sun.star.awt.Key.NUM0)), + new KeyIdentifierInfo("1", Short.valueOf(com.sun.star.awt.Key.NUM1)), + new KeyIdentifierInfo("2", Short.valueOf(com.sun.star.awt.Key.NUM2)), + new KeyIdentifierInfo("3", Short.valueOf(com.sun.star.awt.Key.NUM3)), + new KeyIdentifierInfo("4", Short.valueOf(com.sun.star.awt.Key.NUM4)), + new KeyIdentifierInfo("5", Short.valueOf(com.sun.star.awt.Key.NUM5)), + new KeyIdentifierInfo("6", Short.valueOf(com.sun.star.awt.Key.NUM6)), + new KeyIdentifierInfo("7", Short.valueOf(com.sun.star.awt.Key.NUM7)), + new KeyIdentifierInfo("8", Short.valueOf(com.sun.star.awt.Key.NUM8)), + new KeyIdentifierInfo("9", Short.valueOf(com.sun.star.awt.Key.NUM9)), + new KeyIdentifierInfo("A", Short.valueOf(com.sun.star.awt.Key.A)), + new KeyIdentifierInfo("B", Short.valueOf(com.sun.star.awt.Key.B)), + new KeyIdentifierInfo("C", Short.valueOf(com.sun.star.awt.Key.C)), + new KeyIdentifierInfo("D", Short.valueOf(com.sun.star.awt.Key.D)), + new KeyIdentifierInfo("E", Short.valueOf(com.sun.star.awt.Key.E)), + new KeyIdentifierInfo("F", Short.valueOf(com.sun.star.awt.Key.F)), + new KeyIdentifierInfo("G", Short.valueOf(com.sun.star.awt.Key.G)), + new KeyIdentifierInfo("H", Short.valueOf(com.sun.star.awt.Key.H)), + new KeyIdentifierInfo("I", Short.valueOf(com.sun.star.awt.Key.I)), + new KeyIdentifierInfo("J", Short.valueOf(com.sun.star.awt.Key.J)), + new KeyIdentifierInfo("K", Short.valueOf(com.sun.star.awt.Key.K)), + new KeyIdentifierInfo("L", Short.valueOf(com.sun.star.awt.Key.L)), + new KeyIdentifierInfo("M", Short.valueOf(com.sun.star.awt.Key.M)), + new KeyIdentifierInfo("N", Short.valueOf(com.sun.star.awt.Key.N)), + new KeyIdentifierInfo("O", Short.valueOf(com.sun.star.awt.Key.O)), + new KeyIdentifierInfo("P", Short.valueOf(com.sun.star.awt.Key.P)), + new KeyIdentifierInfo("Q", Short.valueOf(com.sun.star.awt.Key.Q)), + new KeyIdentifierInfo("R", Short.valueOf(com.sun.star.awt.Key.R)), + new KeyIdentifierInfo("S", Short.valueOf(com.sun.star.awt.Key.S)), + new KeyIdentifierInfo("T", Short.valueOf(com.sun.star.awt.Key.T)), + new KeyIdentifierInfo("U", Short.valueOf(com.sun.star.awt.Key.U)), + new KeyIdentifierInfo("V", Short.valueOf(com.sun.star.awt.Key.V)), + new KeyIdentifierInfo("W", Short.valueOf(com.sun.star.awt.Key.W)), + new KeyIdentifierInfo("X", Short.valueOf(com.sun.star.awt.Key.X)), + new KeyIdentifierInfo("Y", Short.valueOf(com.sun.star.awt.Key.Y)), + new KeyIdentifierInfo("Z", Short.valueOf(com.sun.star.awt.Key.Z)), + new KeyIdentifierInfo("F1", Short.valueOf(com.sun.star.awt.Key.F1)), + new KeyIdentifierInfo("F2", Short.valueOf(com.sun.star.awt.Key.F2)), + new KeyIdentifierInfo("F3", Short.valueOf(com.sun.star.awt.Key.F3)), + new KeyIdentifierInfo("F4", Short.valueOf(com.sun.star.awt.Key.F4)), + new KeyIdentifierInfo("F5", Short.valueOf(com.sun.star.awt.Key.F5)), + new KeyIdentifierInfo("F6", Short.valueOf(com.sun.star.awt.Key.F6)), + new KeyIdentifierInfo("F7", Short.valueOf(com.sun.star.awt.Key.F7)), + new KeyIdentifierInfo("F8", Short.valueOf(com.sun.star.awt.Key.F8)), + new KeyIdentifierInfo("F9", Short.valueOf(com.sun.star.awt.Key.F9)), + new KeyIdentifierInfo("F10", Short.valueOf(com.sun.star.awt.Key.F10)), + new KeyIdentifierInfo("F11", Short.valueOf(com.sun.star.awt.Key.F11)), + new KeyIdentifierInfo("F12", Short.valueOf(com.sun.star.awt.Key.F12)), + new KeyIdentifierInfo("DOWN", Short.valueOf(com.sun.star.awt.Key.DOWN)), + new KeyIdentifierInfo("UP", Short.valueOf(com.sun.star.awt.Key.UP)), + new KeyIdentifierInfo("LEFT", Short.valueOf(com.sun.star.awt.Key.LEFT)), + new KeyIdentifierInfo("RIGHT", Short.valueOf(com.sun.star.awt.Key.RIGHT)), + new KeyIdentifierInfo("HOME", Short.valueOf(com.sun.star.awt.Key.HOME)), + new KeyIdentifierInfo("END", Short.valueOf(com.sun.star.awt.Key.END)), + new KeyIdentifierInfo("PAGEUP", Short.valueOf(com.sun.star.awt.Key.PAGEUP)), + new KeyIdentifierInfo("PAGEDOWN", Short.valueOf(com.sun.star.awt.Key.PAGEDOWN)), + new KeyIdentifierInfo("RETURN", Short.valueOf(com.sun.star.awt.Key.RETURN)), + new KeyIdentifierInfo("ESCAPE", Short.valueOf(com.sun.star.awt.Key.ESCAPE)), + new KeyIdentifierInfo("TAB", Short.valueOf(com.sun.star.awt.Key.TAB)), + new KeyIdentifierInfo("BACKSPACE", Short.valueOf(com.sun.star.awt.Key.BACKSPACE)), + new KeyIdentifierInfo("SPACE", Short.valueOf(com.sun.star.awt.Key.SPACE)), + new KeyIdentifierInfo("INSERT", Short.valueOf(com.sun.star.awt.Key.INSERT)), + new KeyIdentifierInfo("DELETE", Short.valueOf(com.sun.star.awt.Key.DELETE)), + new KeyIdentifierInfo("ADD", Short.valueOf(com.sun.star.awt.Key.ADD)), + new KeyIdentifierInfo("SUBTRACT", Short.valueOf(com.sun.star.awt.Key.SUBTRACT)), + new KeyIdentifierInfo("MULTIPLY", Short.valueOf(com.sun.star.awt.Key.MULTIPLY)), + new KeyIdentifierInfo("DIVIDE", Short.valueOf(com.sun.star.awt.Key.DIVIDE)), + new KeyIdentifierInfo("CUT", Short.valueOf(com.sun.star.awt.Key.CUT)), + new KeyIdentifierInfo("COPY", Short.valueOf(com.sun.star.awt.Key.COPY)), + new KeyIdentifierInfo("PASTE", Short.valueOf(com.sun.star.awt.Key.PASTE)), + new KeyIdentifierInfo("UNDO", Short.valueOf(com.sun.star.awt.Key.UNDO)), + new KeyIdentifierInfo("REPEAT", Short.valueOf(com.sun.star.awt.Key.REPEAT)) + }; + + aIdentifierHashMap = new IdentifierHashMap(); + aCodeHashMap = new CodeHashMap(); + for (int i = 0; i + *
  • NoOffice=yes - StarOffice is not started initially.
  • + * + */ +public class DesktopTerminate +{ + + private XMultiServiceFactory xMSF; + private static final int iOfficeCloseTime = 1000; + + /** + * Test if all available document types change the + * persistent Window Attributes + * + * The test follows basically these steps: + * - Create a configuration reader and a componentloader + * - Look for all document types in the configuration + * - Do for every doc type + * - start office + * - read configuration attribute settings + * - create a new document + * - resize the document and close it + * - close office + * - start office + * - read configuration attribute settings + * - create another new document + * - compare old settings with new ones: should be different + * - compare the document size with the resized document: should be equal + * - close office + * - Test finished + */ + @Test public void checkPersistentWindowState() + { + try + { + + System.out.println("Connect the first time."); + + if (!connect()) + { + return; + } + + if (!disconnect()) + { + return; + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private boolean connect() + { + try + { + xMSF = getMSF(); + util.utils.pause(10000); + } + catch (java.lang.Exception e) + { + System.out.println(e.getClass().getName()); + System.out.println("Message: " + e.getMessage()); + fail("Cannot connect the Office."); + return false; + } + return true; + } + + private boolean disconnect() + { + try + { + XDesktop desk = null; + desk = UnoRuntime.queryInterface(XDesktop.class, xMSF.createInstance("com.sun.star.frame.Desktop")); + desk.terminate(); + System.out.println("Waiting " + iOfficeCloseTime + " milliseconds for the Office to close down"); + util.utils.pause(iOfficeCloseTime); + xMSF = null; + } + catch (java.lang.Exception e) + { + e.printStackTrace(); + fail("Cannot dispose the Office."); + return false; + } + return true; + } + + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass public static void setUpConnection() throws Exception { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass public static void tearDownConnection() + { + System.out.println("tearDownConnection()"); + // don't do a tearDown here, desktop is already terminated. + } + + private static final OfficeConnection connection = new OfficeConnection(); + +} diff --git a/framework/qa/complex/dispatches/Interceptor.java b/framework/qa/complex/dispatches/Interceptor.java new file mode 100644 index 000000000..ecbac4421 --- /dev/null +++ b/framework/qa/complex/dispatches/Interceptor.java @@ -0,0 +1,338 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package complex.dispatches; + +// __________ Imports __________ + +// structs, const, ... +import com.sun.star.beans.PropertyValue; + +// exceptions +import com.sun.star.frame.DispatchDescriptor; +import com.sun.star.frame.XDispatch; +import com.sun.star.frame.XDispatchProvider; +import com.sun.star.frame.XDispatchProviderInterceptor; +import com.sun.star.frame.XInterceptorInfo; +import com.sun.star.frame.XStatusListener; + +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.awt.XDataTransferProviderAccess; + +// helper +import com.sun.star.util.URL; +import com.sun.star.uno.UnoRuntime; + +// __________ Implementation __________ + +/** + * implements a configurable interceptor for dispatch events. + */ +public class Interceptor implements XDispatch, + XDispatchProviderInterceptor, + XInterceptorInfo +{ + /** contains the list of interception URL schema's (wildcards are allowed there!) + supported by this interceptor. It can be set from outside. + If no external URLs are set, the default "*" is used instead. + That would have the same effect as if this implementation would not support the + interface XInterceptorInfo ! + */ + private String[] m_lURLs4InterceptionInfo = null; + + + + /** These URL's will be blocked by this interceptor. + Can be set from outside. Every queryDispatch() for these + set of URL's will be answered with an empty dispatch object! + If no external URLs are set the default "*" is used instead. + So every incoming URL will be blocked .-) + */ + private String[] m_lURLs4Blocking = null; + + + + /** Every dispatch interceptor knows it's master and slave interceptor + of the dispatch chain. These values must be stupid handled .-) + They have to be set and reset in case the right interface methods are called. + Nothing more. It's not allowed to dispose() it. + The slave can be used inside queryDispatch() to forward requests, + which are not handled by this interceptor instance. + */ + private XDispatchProvider m_xSlave = null; + private XDispatchProvider m_xMaster = null; + + + + /** counts calls of setSlave...(). + So the outside API test can use this value to know if this interceptor + was really added to the interceptor chain of OOo. + */ + private int m_nRegistrationCount = 0; + + + + /** indicates if this interceptor object is currently part of the interceptor + chain of OOo. Only true if a valid slave or master dispatch is set on this + instance. + */ + private boolean m_bIsRegistered = false; + + /** points to the global uno service manager. */ + private XMultiServiceFactory m_xMSF = null; + + public Interceptor(XMultiServiceFactory xMSF) + { + m_xMSF = xMSF; + } + + + /** XInterceptorInfo */ + public synchronized String[] getInterceptedURLs() + { + return impl_getURLs4InterceptionInfo(); + } + + + + /** XDispatchProviderInterceptor */ + public synchronized XDispatchProvider getSlaveDispatchProvider() + { + System.out.println("Interceptor.getSlaveDispatchProvider() called"); + return m_xSlave; + } + + + + /** XDispatchProviderInterceptor */ + public synchronized XDispatchProvider getMasterDispatchProvider() + { + System.out.println("Interceptor.getMasterDispatchProvider() called"); + return m_xMaster; + } + + + + /** XDispatchProviderInterceptor */ + public synchronized void setSlaveDispatchProvider(XDispatchProvider xSlave) + { + System.out.println("Interceptor.setSlaveDispatchProvider("+xSlave+") called"); + + if (xSlave != null) + { + ++m_nRegistrationCount; + m_bIsRegistered = true; + } + else + { + m_bIsRegistered = false; + } + + m_xSlave = xSlave; + } + + /** XDispatchProviderInterceptor */ + public synchronized void setMasterDispatchProvider(XDispatchProvider xMaster) + { + System.out.println("Interceptor.setMasterDispatchProvider("+xMaster+") called"); + m_xMaster = xMaster; + } + + private XDataTransferProviderAccess m_xToolkit = null; + + /** A beautiful method whose only purpose is to take and release a + * solar mutex. If this hangs - you can see a beautiful deadlock + * when you attach your debugger to the main process. + */ + private void checkNoSolarMutexHeld() + { + try + { + if (m_xToolkit == null) + m_xToolkit = UnoRuntime.queryInterface( + XDataTransferProviderAccess.class, + m_xMSF.createInstance("com.sun.star.awt.Toolkit")); + + // A Method notable only for taking the solar mutex. + System.out.println("Check solarmutex not held - if so deadlock"); + m_xToolkit.getDragSource( null ); + System.out.println("Solarmutex not held."); + } catch (java.lang.Throwable ex) { + System.out.println("Failed to create and invoke toolkit method " + ex.toString()); + } + } + + /** XDispatchProvider + */ + public synchronized XDispatch queryDispatch(URL aURL, + String sTargetFrameName, + int nSearchFlags) + { + System.out.println("Interceptor.queryDispatch('"+aURL.Complete+"', '"+sTargetFrameName+"', "+nSearchFlags+") called"); + + checkNoSolarMutexHeld(); + + if (impl_isBlockedURL(aURL.Complete)) + { + System.out.println("Interceptor.queryDispatch(): URL blocked => returns NULL"); + return null; + } + + if (m_xSlave != null) + { + System.out.println("Interceptor.queryDispatch(): ask slave ..."); + return m_xSlave.queryDispatch(aURL, sTargetFrameName, nSearchFlags); + } + + System.out.println("Interceptor.queryDispatch(): no idea => returns this"); + return this; + } + + + + /** XDispatchProvider + */ + public XDispatch[] queryDispatches(DispatchDescriptor[] lRequests) + { + int i = 0; + int c = lRequests.length; + + XDispatch[] lResults = new XDispatch[c]; + for (i=0; i aCheckMap = new HashMap(c2); + for (i2 = 0; i2 < c2; ++i2) + { + DispatchInformation aInfo = lInfos[i2]; + if (aInfo.GroupId != nGroup) + { + // Error + fail("At least one DispatchInformation item does not match the requested group.\n\trequested group=[" + nGroup + + "] returned group=[" + aInfo.GroupId + "] command=\"" + aInfo.Command + "\""); // true => don't break this test + continue; + } + + if (aCheckMap.containsKey(aInfo.Command)) + { + // Error + fail("Found a duplicate item: group=[" + aInfo.GroupId + "] command=\"" + aInfo.Command + "\""); // true => don't break this test + continue; + } + + aCheckMap.put(aInfo.Command, aInfo.Command); + System.out.println("\t[" + aInfo.GroupId + "] \"" + aInfo.Command + "\""); + } + } + } + + private synchronized XFrame impl_createNewFrame() + { + XFrame xFrame = m_xDesktop.findFrame("_blank", 0); + xFrame.getContainerWindow().setVisible(true); + return xFrame; + } + + private synchronized void impl_closeFrame(XFrame xFrame) throws Exception + { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xFrame); + xClose.close(false); + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + private static final OfficeConnection connection = new OfficeConnection(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java b/framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java new file mode 100644 index 000000000..fd7fffcb3 --- /dev/null +++ b/framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java @@ -0,0 +1,82 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package complex.disposing; + +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.frame.XDesktop; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; + + +/** + * This test is for bug110698. The Office is closed and is continually connected + * while it closes. This did let the Office freeze. Now when the Office is + * closed, the connection is refused. + */ +public class GetServiceWhileDisposingOffice +{ + + @Test public void checkServiceWhileDisposing() throws Exception + { + XMultiServiceFactory xMSF = getMSF(); + XDesktop xDesktop = null; + + xDesktop = UnoRuntime.queryInterface(XDesktop.class, xMSF.createInstance("com.sun.star.frame.Desktop")); + int step = 0; + try + { + System.out.println("Start the termination of the Office."); + xDesktop.terminate(); + for (; step < 10000; step++) + { + xMSF.createInstance("com.sun.star.frame.Desktop"); + } + } + catch (com.sun.star.lang.DisposedException e) + { + System.out.println("DisposedException in step: " + step); + } + } + + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + { + System.out.println("tearDownConnection()"); + // Office is already terminated. + } + private static final OfficeConnection connection = new OfficeConnection(); + +} diff --git a/framework/qa/complex/framework/autosave/AutoSave.java b/framework/qa/complex/framework/autosave/AutoSave.java new file mode 100644 index 000000000..c6e7549d0 --- /dev/null +++ b/framework/qa/complex/framework/autosave/AutoSave.java @@ -0,0 +1,451 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.framework.autosave; + + + +import com.sun.star.beans.PropertyValue; +import com.sun.star.frame.FeatureStateEvent; +import com.sun.star.frame.XDispatch; +import com.sun.star.frame.XDispatchProvider; +import com.sun.star.frame.XModel; +import com.sun.star.frame.XStatusListener; +import com.sun.star.frame.theAutoRecovery; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.sheet.FillDirection; +import com.sun.star.sheet.XCellSeries; +import com.sun.star.table.XCellRange; +import com.sun.star.util.XCloseable; +import com.sun.star.sheet.XSpreadsheet; +import com.sun.star.sheet.XSpreadsheetDocument; +import com.sun.star.sheet.XSpreadsheets; +import com.sun.star.uno.AnyConverter; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.util.URL; +import com.sun.star.util.XURLTransformer; +import java.util.*; +import util.utils; + + +// ---------- junit imports ----------------- +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; +import util.SOfficeFactory; +import static org.junit.Assert.*; + + + +/** @short Check some use cases of the AutoSave feature + */ +public class AutoSave +{ + + private static class AutoSaveListener implements XStatusListener + { + private XDispatch m_xAutoSave; + private URL m_aRegistration; + private final Protocol m_aLog; + + private AutoSaveListener(XMultiServiceFactory xSMGR , + XDispatch xAutoSave, + Protocol aLog ) + { + m_aLog = aLog; + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "create listener for AutoSave notifications ..."); + + try + { + m_xAutoSave = xAutoSave; + + XURLTransformer xParser = UnoRuntime.queryInterface(XURLTransformer.class, xSMGR.createInstance("com.sun.star.util.URLTransformer")); + URL[] aURL = new URL[1]; + aURL[0] = new URL(); + aURL[0].Complete = "vnd.sun.star.autorecovery:/doAutoSave"; + xParser.parseStrict(aURL); + m_aRegistration = aURL[0]; + + m_xAutoSave.addStatusListener(this, m_aRegistration); + m_aLog.log(Protocol.TYPE_INFO, "successfully registered as AutoSave listener."); + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, ""); + } + + private void disableListener() + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "stop listening for AutoSave notifications ..."); + + XDispatch xAutoSave = null; + URL aRegURL = null; + synchronized (this) + { + xAutoSave = m_xAutoSave; + aRegURL = m_aRegistration; + } + + try + { + if ( + (xAutoSave != null) && + (aRegURL != null) + ) + xAutoSave.removeStatusListener(this, aRegURL); + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, ""); + } + + public void statusChanged(FeatureStateEvent aEvent) + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "statusChanged() called from AutoSave ..."); + + m_aLog.log("FeatureURL = \""+aEvent.FeatureURL.Complete+"\"" ); + m_aLog.log("FeatureDescriptor = \""+aEvent.FeatureDescriptor+"\"" ); + m_aLog.log("IsEnabled = \""+aEvent.IsEnabled+"\"" ); + m_aLog.log("Requery = \""+aEvent.Requery+"\"" ); + m_aLog.log("State:" ); + m_aLog.log(aEvent.State ); + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, ""); + } + + public void disposing(com.sun.star.lang.EventObject aEvent) + { + m_aLog.log(Protocol.TYPE_INFO, "disposing() called from AutoSave."); + synchronized(this) + { + m_xAutoSave = null; + m_aRegistration = null; + } + } + } + + + // some const + + + // member + + private Protocol m_aLog; + + /** points to the global uno service manager. */ + private XMultiServiceFactory m_xSMGR = null; + + private SOfficeFactory m_aSOF; + + /** can be used to trigger/enable/disable the AutoSave feature. */ + private XDispatch m_xAutoSave = null; + + private XURLTransformer m_xURLParser = null; + + + // test environment + + + /** @short Create the environment for following tests. + + @descr create an empty test frame, where we can load + different components inside. + */ + @Before public void before() + { + m_aLog = new Protocol(Protocol.MODE_HTML | Protocol.MODE_STDOUT, Protocol.FILTER_NONE, utils.getUsersTempDir() + "/complex_log_ascii_01.html"); + + try + { + // get uno service manager from global test environment + m_xSMGR = getMSF(); + + // get another helper to e.g. create test documents + m_aSOF = SOfficeFactory.getFactory(m_xSMGR); + + // create AutoSave instance + m_xAutoSave = theAutoRecovery.get(connection.getComponentContext()); + + // prepare AutoSave + // make sure it will be started every 1 min + ConfigHelper aConfig = new ConfigHelper(connection.getComponentContext(), "org.openoffice.Office.Recovery", false); + aConfig.writeRelativeKey("AutoSave", "Enabled" , Boolean.TRUE ); + aConfig.writeRelativeKey("AutoSave", "TimeIntervall", Integer.valueOf(1)); // 1 min + aConfig.flush(); + aConfig = null; + + // is needed to parse dispatch commands + m_xURLParser = UnoRuntime.queryInterface(XURLTransformer.class, m_xSMGR.createInstance("com.sun.star.util.URLTransformer")); + + } + catch(java.lang.Throwable ex) + { + m_aLog.log(ex); + fail("Couldn't create test environment"); + } + } + + + /** @short close the environment. + */ + @After public void after() + { + // ??? + } + + + // create a calc document with content, which needs some time for saving + private XInterface createBigCalcDoc() + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "createBigCalcDoc() started ..."); + try + { + m_aLog.log("Create empty calc document for testing."); + XSpreadsheetDocument xSheetDoc = m_aSOF.createCalcDoc("_default"); + m_aLog.log("Retrieve first sheet from calc document."); + XSpreadsheets xSheets = xSheetDoc.getSheets(); + XSpreadsheet xSheet = (XSpreadsheet)AnyConverter.toObject( + new Type(XSpreadsheet.class), + xSheets.getByName( + xSheets.getElementNames()[0])); + m_aLog.log("Fill two cells with value and formula."); + xSheet.getCellByPosition(0, 0).setValue(1); + xSheet.getCellByPosition(0, 1).setFormula("=a1+1"); + m_aLog.log("Retrieve big range."); + XCellRange xRange = xSheet.getCellRangeByName("A1:Z9999"); + XCellSeries xSeries = UnoRuntime.queryInterface(XCellSeries.class, xRange); + m_aLog.log("Duplicate cells from top to bottom inside range."); + xSeries.fillAuto(FillDirection.TO_BOTTOM, 2); + m_aLog.log("Duplicate cells from left to right inside range."); + xSeries.fillAuto(FillDirection.TO_RIGHT , 1); + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE | Protocol.TYPE_OK, "createBigCalcDoc() finished."); + return xSheetDoc; + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "createBigCalcDoc() finished."); + return null; + } + + + private void saveDoc(XInterface xDoc, + String sURL) + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "saveDoc('"+sURL+"') started ..."); + try + { + URL[] aURL = new URL[1]; + aURL[0] = new URL(); + aURL[0].Complete = ".uno:SaveAs"; + m_xURLParser.parseStrict(aURL); + + XModel xModel = UnoRuntime.queryInterface(XModel.class, xDoc); + XDispatchProvider xProvider = UnoRuntime.queryInterface(XDispatchProvider.class, xModel.getCurrentController()); + XDispatch xDispatch = xProvider.queryDispatch(aURL[0], "_self", 0); + + PropertyValue[] lArgs = new PropertyValue[3]; + lArgs[0] = new PropertyValue(); + lArgs[0].Name = "URL"; + lArgs[0].Value = sURL; + lArgs[1] = new PropertyValue(); + lArgs[1].Name = "Overwrite"; + lArgs[1].Value = Boolean.TRUE; + lArgs[2] = new PropertyValue(); + lArgs[2].Name = "StoreTo"; + lArgs[2].Value = Boolean.TRUE; + + xDispatch.dispatch(aURL[0], lArgs); + + m_aLog.log(Protocol.TYPE_OK, "saveDoc('"+sURL+"') = OK."); + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "saveDoc('"+sURL+"') finished."); + } + + + private void closeDoc(XInterface xDoc) + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "closeDoc() started ..."); + + try + { + Random aRandom = new Random(); + int nRetry = 5; + while(nRetry>0) + { + try + { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xDoc); + if (xClose != null) + { + xClose.close(false); + m_aLog.log(Protocol.TYPE_OK, "closeDoc() = OK."); + nRetry = 0; + } + else + { + m_aLog.log(Protocol.TYPE_ERROR, "closeDoc() = ERROR. Doc doesn't provide needed interface!"); + } + } + catch(com.sun.star.util.CloseVetoException exVeto) + { + m_aLog.log(Protocol.TYPE_WARNING , "got CloseVetoException on calling doc.close()." ); + m_aLog.log(Protocol.TYPE_WARNING_INFO, "Please check the reason for that more in detail." ); + m_aLog.log(Protocol.TYPE_WARNING_INFO, "A message like \"Can not close while saving.\" was intended and doesn't show an error!"); + m_aLog.log(Protocol.TYPE_WARNING_INFO, exVeto.getMessage()); + } + + if (nRetry > 0) + { + --nRetry; + long nWait = aRandom.nextInt(30000); // 30 sec. + try + { + m_aLog.log(Protocol.TYPE_INFO, "sleep for "+nWait+" ms"); + synchronized(this) + { + wait(nWait); + } + } + catch(Throwable ex) + { + m_aLog.log(Protocol.TYPE_WARNING , "got exception for wait() !?"); + m_aLog.log(Protocol.TYPE_WARNING_INFO, ex.getMessage()); + } + } + } + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "closeDoc() finished."); + } + + private class DocThread extends Thread + { + DocThread() + {} + + @Override + public void run() + { + impl_checkConcurrentAutoSaveToNormalUISave(); + } + } + + + /** @short check concurrent save requests to the same document + * at the same time. + * + * @descr First we simulate an UI save by dispatching the right URL + * to the document and at the same time we try to trigger an AutoSave + * from another thread. So these operations should be started at the same time. + * It should not crash. The AutoSave request must be postponed. + */ + @Test public void checkConcurrentAutoSaveToNormalUISave() + { + m_aLog.log(Protocol.TYPE_TESTMARK , "AutoSave"); + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "checkConcurrentAutoSaveToNormalUISave()"); + + AutoSaveListener xListener = new AutoSaveListener(m_xSMGR, m_xAutoSave, m_aLog); + + try + { + DocThread aThread = new DocThread(); + aThread.start(); + aThread.join(); + } + catch(Throwable ex) + {} + + xListener.disableListener(); + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "checkConcurrentAutoSaveToNormalUISave()"); + m_aLog.logStatistics(); + } + + public void impl_checkConcurrentAutoSaveToNormalUISave() + { + Random aRandom = new Random(); + + int i = 0; + int c = 5; + for (i=0; i"); + + // insert line number + if (m_nLine % MARK_DIFF == 0) + impl_generateColoredHTMLCell(sLine, Long.toString(m_nLine), BGCOLOR_LINECOL, FGCOLOR_LINECOL_MARKED, true); + else + impl_generateColoredHTMLCell(sLine, Long.toString(m_nLine), BGCOLOR_LINECOL, FGCOLOR_LINECOL_NORMAL, false); + + // add time stamp + impl_generateColoredHTMLCell(sLine, m_aStamp.toString()+" ", BGCOLOR_TIMESTAMP, FGCOLOR_TIMESTAMP, false); + + // add log type info + boolean bTypeCellFilled = false; + if ((m_nType & TYPE_ERROR_INFO) == TYPE_ERROR_INFO) + { + impl_generateColoredHTMLCell(sLine, "ERROR INFO", BGCOLOR_ERROR_INFO, FGCOLOR_ERROR_INFO, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_ERROR) == TYPE_ERROR) + { + impl_generateColoredHTMLCell(sLine, "ERROR", BGCOLOR_ERROR, FGCOLOR_ERROR, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_WARNING_INFO) == TYPE_WARNING_INFO) + { + impl_generateColoredHTMLCell(sLine, "WARNING INFO", BGCOLOR_WARNING_INFO, FGCOLOR_WARNING_INFO, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_WARNING) == TYPE_WARNING) + { + impl_generateColoredHTMLCell(sLine, "WARNING", BGCOLOR_WARNING, FGCOLOR_WARNING, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_OK) == TYPE_OK) + { + impl_generateColoredHTMLCell(sLine, "OK", BGCOLOR_OK, FGCOLOR_OK, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_INFO) == TYPE_INFO) + { + impl_generateColoredHTMLCell(sLine, "INFO", BGCOLOR_INFO, FGCOLOR_INFO, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK) + { + impl_generateColoredHTMLCell(sLine, "TEST", BGCOLOR_TESTMARK, FGCOLOR_TESTMARK, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_STATISTIC) == TYPE_STATISTIC) + { + impl_generateColoredHTMLCell(sLine, "STATISTIC", BGCOLOR_STATISTIC, FGCOLOR_STATISTIC, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_LINK) == TYPE_LINK) + { + impl_generateColoredHTMLCell(sLine, "LINK", BGCOLOR_LINK, FGCOLOR_LINK, false); + bTypeCellFilled = true; + } + else + if ( + ((m_nType & TYPE_SCOPE_OPEN ) == TYPE_SCOPE_OPEN ) || + ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + ) + { + impl_generateColoredHTMLCell(sLine, "SCOPE", BGCOLOR_SCOPE, FGCOLOR_SCOPE, false); + bTypeCellFilled = true; + } + + // if no type information was added to the current column, we must + // write any content into this cell. Otherwise some browser + // shows a strange layout! + if (! bTypeCellFilled) + impl_generateColoredHTMLCell(sLine, " ", BGCOLOR_STANDARD, FGCOLOR_STANDARD, false); + + // add scope information + sLine.append(""); + for (int s=0; s{ "+m_nScope+""); + else + if ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + sLine.append(""+m_nScope+" }"); + sLine.append("\n"); + + // add message + sLine.append("" ); + sLine.append(m_sMessage); + sLine.append("\n" ); + + sLine.append("\n" ); + + return sLine.toString(); + } + + /** detect, if this line object represent an error */ + public synchronized boolean isError() + { + return ( + ((m_nType & TYPE_ERROR) == TYPE_ERROR) && + ((m_nType & TYPE_INFO ) != TYPE_INFO ) + ); + } + + /** detect, if this line object represent a warning */ + public synchronized boolean isWarning() + { + return ( + ((m_nType & TYPE_WARNING) == TYPE_WARNING) && + ((m_nType & TYPE_INFO ) != TYPE_INFO ) + ); + } + + /** detect, if this line object represent a marked position */ + public synchronized boolean isTestMark() + { + return ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK); + } + + /** + * create a colored table cell formatted as HTML. + * + * @param sCell + * an outside string buffer, which can be + * used to generate the + * needed HTML code there. + * + * @param sContent + * the text content of this cell. + * + * @param sBGColor + * a string, which represent the background color + * coded in HTML. + * + * @param sFGColor + * a string, which represent the foreground color + * coded in HTML. + * + * @param bBold + * enable/disable bold state for the text content. + */ + private void impl_generateColoredHTMLCell(StringBuffer sCell , + String sContent, + String sBGColor, + String sFGColor, + boolean bBold ) + { + sCell.append(""); + sCell.append(""); + if (bBold) + sCell.append(""); + sCell.append(sContent); + if (bBold) + sCell.append(""); + sCell.append("\n"); + } + } + + + /** + * ctor + * It creates a new instance of this class and initializes it in the right mode. + * + * @param nMode + * specify how the log should be generated. + * + * @param nFilter + * can be used to filter log messages by its type. + * + * @param sFileName + * the name of the log file (if nMode requires a log file) + */ + public Protocol(int nMode , + int nFilter , + String sFileName) + { + m_nMode = nMode; + m_nFilter = nFilter; + m_sFileName = sFileName; + m_nLine = 0; + m_nScope = 1; + m_nWarnings = 0; + m_nErrors = 0; + m_aStartTime = new Timestamp(System.currentTimeMillis()); + } + + + + + + /** + * log an unspecified message. + * + * Sometimes it's not necessary to set a special type for a message. + * The pure message seems to be enough. The type of such "pure messages" + * will be set to INFO. + * + * @param sMessage + * the pure message + * + * @see #log(int, String) + */ + public synchronized void log( /*IN*/ String sMessage ) + { + log(TYPE_INFO, sMessage); + } + + + /** + * log an exception. + * + * It uses all information available by this exception object + * to generate the log. So exceptions are printed out using a + * standard format. + * + * @param exThrowable + * the exception + */ + public synchronized void log( /*IN*/ Throwable exThrowable ) + { + log(TYPE_SCOPE_OPEN | TYPE_ERROR, "exception \""+exThrowable.getMessage()+"\""); + + StackTraceElement[] lStack = exThrowable.getStackTrace(); + for (int i=0; i 0 ) && + ((nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + ) + { + --m_nScope; + } + + // update statistic values + if (aLine.isTestMark()) + ++m_nTestMarks; + if (aLine.isWarning()) + ++m_nWarnings; + if (aLine.isError()) + ++m_nErrors; + + // no else - it's a bit field of possible reactions! + if ((m_nMode & MODE_STDOUT) == MODE_STDOUT) + System.out.print(sAsciiLog); + // no else - it's a bit field of possible reactions! + if ((m_nMode & MODE_STDERR) == MODE_STDERR) + System.err.print(sAsciiLog); + // no else - it's a bit field of possible reactions! + // But these both conditions must be handled together. + // Because we can't generate different types of log contents to the same log file. + // We prefer HTML if both types are set. + if ( + ((m_nMode & MODE_HTML ) == MODE_HTML ) || + ((m_nMode & MODE_ASCII) == MODE_ASCII) + ) + { + boolean bAppend = (m_nLine>1); + String sContent; + if ((m_nMode & MODE_HTML) == MODE_HTML) + { + if (! bAppend) + sContent = impl_generateHTMLHeader()+sHTMLLog; + else + sContent = sHTMLLog; + } + else + { + if (! bAppend) + sContent = impl_generateAsciiHeader()+sAsciiLog; + else + sContent = sAsciiLog; + } + + impl_writeToLogFile(m_sFileName, bAppend, sContent); + } + } + + + + + + /** + * log the current statistic values + * We write it into our protocol buffer and + * reset it. + */ + public synchronized void logStatistics() + { + Timestamp aEndTime = new Timestamp(System.currentTimeMillis()); + Timestamp aDiff = new Timestamp(aEndTime.getTime()-m_aStartTime.getTime()); + + int nLogType = TYPE_STATISTIC; + if (m_nErrors > 0) + nLogType = TYPE_ERROR_INFO; + else + if (m_nWarnings > 0) + nLogType = TYPE_WARNING_INFO; + + log(nLogType | TYPE_SCOPE_OPEN , "statistic:" ); + log(nLogType , "tests = "+m_nTestMarks ); + log(nLogType , "errors = "+m_nErrors ); + log(nLogType , "warnings = "+m_nWarnings ); + log(nLogType , "elapsed time = "+aDiff.toString()); + log(nLogType | TYPE_SCOPE_CLOSE, "" ); + + resetStatistics(); + } + + private synchronized void resetStatistics() + { + m_nTestMarks = 0; + m_nWarnings = 0; + m_nErrors = 0; + m_aStartTime = new Timestamp(System.currentTimeMillis()); + } + + + /** + * returns a generic html header for generating html log files + * + * It's used from the method finish() to generate a valid html formatted file. + * For that it's necessary to open some special html targets like e.g. . + * + * @return A string, which includes the whole header. + * + * @see #finish() + * @see #impl_generateHTMLFooter() + */ + private String impl_generateHTMLHeader() + { + return "\n\n"+m_sFileName+"\n\n\n\n"; + } + + private String impl_generateAsciiHeader() + { + return "********************************************************************************\n"; + } + + /** + * helper to log different representations of a property(array) + * + * @param sOut + * used to generate the log output there. + * + * @param lProps + * represent the property(array) to be logged. + */ + private void impl_logPropertyArray( /*OUT*/ StringBuffer sOut , + /*IN */ com.sun.star.beans.PropertyValue[] lProps ) + { + int i = 0; + int c = lProps.length; + + for (i=0; i] {"); + sOut.append("}"); + } + else + if (aAny instanceof com.sun.star.beans.PropertyValue[]) + { + sOut.append("[sequence< PropertyValue >] {"); + com.sun.star.beans.PropertyValue[] lSubProps = (com.sun.star.beans.PropertyValue[])com.sun.star.uno.AnyConverter.toArray(aAny); + impl_logPropertyArray(sOut, lSubProps); + sOut.append("}"); + } + else + if (aAny instanceof com.sun.star.beans.NamedValue[]) + { + sOut.append("[sequence< NamedValue >] {"); + com.sun.star.beans.NamedValue[] lSubProps = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(aAny); + impl_logPropertyArray(sOut, lSubProps); + sOut.append("}"); + } + else + { + sOut.append("[unknown array] {-}"); + } + } + else + if (com.sun.star.uno.AnyConverter.isObject(aAny)) + { + sOut.append("[object] {"); + // TODO + sOut.append("}"); + } + + if ((m_nMode & MODE_HTML) == MODE_HTML) + sOut.append("
    "); + else + sOut.append("\n"); + } + catch(com.sun.star.lang.IllegalArgumentException exIll) + { + sOut.append("Got exception during property conversion.\n"); + sOut.append(exIll.getMessage()); + sOut.append("\n"); + } + } + + + /** + * Writes the given content to the specified log file. + */ + private void impl_writeToLogFile(String sFileName, + boolean bAppend , + String sContent ) + { + try + { + FileWriter aLogFile = new FileWriter(sFileName, bAppend); + aLogFile.write(sContent); + aLogFile.flush(); + aLogFile.close(); + aLogFile = null; + } + catch (java.io.IOException exIO) + { + System.err.println("Can't dump protocol into log file."); + System.err.println(exIO); + exIO.printStackTrace(); + } + } +} diff --git a/framework/qa/complex/framework/recovery/CrashThread.java b/framework/qa/complex/framework/recovery/CrashThread.java new file mode 100644 index 000000000..8a16f83c6 --- /dev/null +++ b/framework/qa/complex/framework/recovery/CrashThread.java @@ -0,0 +1,72 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.framework.recovery; + +import com.sun.star.frame.XController; +import com.sun.star.frame.XDispatch; +import com.sun.star.frame.XDispatchProvider; +import com.sun.star.frame.XModel; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.URL; +import com.sun.star.util.XURLTransformer; + +/** + * Thread to crash the office. This thread dies after the office process + * is nopt longer available. + */ +public class CrashThread extends Thread { + private final XComponent xDoc; + private final XMultiServiceFactory msf; + + public CrashThread(XComponent xDoc, XMultiServiceFactory msf) { + this.xDoc = xDoc; + this.msf = msf; + } + + @Override + public void run() { + try{ + XModel xModel = UnoRuntime.queryInterface(XModel.class, xDoc); + + XController xController = xModel.getCurrentController(); + XDispatchProvider xDispProv = UnoRuntime.queryInterface( + XDispatchProvider.class, + xController); + XURLTransformer xParser = UnoRuntime.queryInterface( + XURLTransformer.class, + msf.createInstance( + "com.sun.star.util.URLTransformer")); + + // Because it's an in/out parameter we must use an array of URL objects. + URL[] aParseURL = new URL[1]; + aParseURL[0] = new URL(); + aParseURL[0].Complete = ".uno:Crash"; + xParser.parseStrict(aParseURL); + + URL aURL = aParseURL[0]; + XDispatch xDispatcher = xDispProv.queryDispatch(aURL, "", 0); + + if (xDispatcher != null) { + xDispatcher.dispatch(aURL, null); + } + } catch (Exception e){} + } +} diff --git a/framework/qa/complex/framework/recovery/KlickButtonThread.java b/framework/qa/complex/framework/recovery/KlickButtonThread.java new file mode 100644 index 000000000..90ecf68c4 --- /dev/null +++ b/framework/qa/complex/framework/recovery/KlickButtonThread.java @@ -0,0 +1,46 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.framework.recovery; + +import com.sun.star.awt.XWindow; +import util.UITools; + +/** + * Thread to crash the office. This thread dies after the office process + * is no longer available. + */ +public class KlickButtonThread extends Thread { + private final XWindow xWindow; + private final String buttonName; + + public KlickButtonThread(XWindow xWindow, String buttonName) { + this.xWindow = xWindow; + this.buttonName = buttonName; + } + + @Override + public void run() { + try{ + UITools oUITools = new UITools(xWindow); + + oUITools.clickButton(buttonName); + + } catch (Exception e){} + } +} diff --git a/framework/qa/complex/framework/recovery/RecoveryTest.java b/framework/qa/complex/framework/recovery/RecoveryTest.java new file mode 100644 index 000000000..ede07b486 --- /dev/null +++ b/framework/qa/complex/framework/recovery/RecoveryTest.java @@ -0,0 +1,611 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.framework.recovery; + +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.awt.Rectangle; +import com.sun.star.awt.Size; +import com.sun.star.awt.XDialog; +import com.sun.star.awt.XWindow; +import com.sun.star.container.XEnumeration; +import com.sun.star.frame.XModel; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.text.ControlCharacter; +import com.sun.star.text.XText; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.uno.UnoRuntime; +import complexlib.ComplexTestCase; +import helper.OfficeProvider; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Toolkit; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Random; +import util.DesktopTools; +import util.PropertyName; +import util.SOfficeFactory; +import util.UITools; +import util.utils; + +public class RecoveryTest extends ComplexTestCase { + + static XMultiServiceFactory xMSF; + static SOfficeFactory SOF; + static RecoveryTools rt; + /** + * If you divide the screen in four parts in the first of them the office + * windows should be placed. The range of the first quarter is stored in the variable. + */ + static Point windowMaxPosition; + /** + * The office windows starts in the first quarter of the screen. In this variable + * the maximum size for the windows was stored so the windows can be placed + * visible on the screen. + */ + static Size windowMaxSize; + + /** + * All office windows will be placed by this test on randomized positions. + * This positions was stored in this Hashmap. The keys are the frame names + * and the values are com sun.star.awt.Rectangle. + * @see com.sun.star.awt.Rectangle + */ + private final HashMap windowsPosSize = new HashMap(); + + /** + * A function to tell the framework, which test functions are available. + * @return All test methods. + * + * @todo: hidden documents + * @todo: running presentation + * @todo: modular dialogs like Hpyerlink-Dialog + * @todo: second view of a document + * @todo: remove recovery data before start test + * @todo: after a second start after the crash there should no documents recovered anymore + * @todo: enable remove of recovery files + */ + @Override + public String[] getTestMethodNames() { + return new String[]{"testCrash"}; + } + + /** Create the environment for following tests. + * Use either a component loader from desktop or + * from frame + */ + public void normalCrash(){ + cleanRecoveryData(); + startOffice(); + generateDesktop(); + makeCrash(); + int expectedDocumentCount = windowsPosSize.size() + 1; + handleRecoveryDialogAfterCrash(expectedDocumentCount); + startOffice(); + handleRecoveryDialog_QuickExit(expectedDocumentCount); + handleCrashReporterDialog(true); + checkDocumentCount(expectedDocumentCount); + } + + public void testCrash(){ + cleanRecoveryData(); + restoreBackupRecoveryData(); + startOffice(); + int expectedDocumentCount = 3; + handleRecoveryDialog_QuickExitAndSave(expectedDocumentCount); + } + + public void before() throws Exception { + + String msg ="\n\n\tPATH TO OFFICE BINARY MISSING!\n"; + msg +="\tPlease run your command with the following parameter:\n\n"; + msg +="\t-AppExecutionCommand=OFFICEBINARY CONNECTIONSTRING\n\n"; + msg +="Example Windows:\n"; + msg +="-AppExecutionCommand=C:\\office\\soffice.exe --accept=socket,host=localhost,port=8101;urp;\n\n"; + msg +="Example UNIX:\n"; + msg +="-AppExecutionCommand=/office/soffice \"--accept=socket,host=localhost,port=8101;urp;\"\n\n"; + msg+="NOTE: on UNIX be sure to have the connection string inside quotation mark!\n"; + + assure(msg, param.get("AppExecutionCommand") != null && ! param.get("AppExecutionCommand").equals("")); + System.out.println("HALLO" + param.get("AppExecutionCommand")); + msg = "\n\nONE PARAMETER IS MISSING!\n"; + msg += "Please append to your command the following parameter:\n\n"; + msg += "\t-NoOffice=true"; + assure(msg, param.getBool("NoOffice")); + + + rt = new RecoveryTools(param ,log); + + rt.removeParametersFromAppExecutionCommand(); + + log.println("start the office to test recovery feature..."); + + // make window ranges + makeWindowPositionRage(); + + } + + private void startOffice(){ + assure("Could not connect to office", connect()); + log.setWatcher(param.get("Watcher")); + } + + + private void checkDocumentCount(int expectedDocumentCount){ + XEnumeration allComp = DesktopTools.getAllComponents(xMSF); + int documentCount = 0; + + try{ + while (allComp.hasMoreElements()){ + allComp.nextElement(); + documentCount ++; + } + } + catch ( com.sun.star.container.NoSuchElementException e){} + catch ( com.sun.star.lang.WrappedTargetException e){} + + String msg ="The amount of documents to recover is different from the expected amount:\n"; + msg += "\texpected:\t" + expectedDocumentCount + "\n"; + msg += "\tto recover:\t" + documentCount; + + assure(msg, expectedDocumentCount == documentCount); + } + + /** + * This function starts an office instance. It uses the AppExecutionCommand parameter. + * @return TRUE if office is connected otherwise FALSE + */ + private boolean connect(){ + try { + + OfficeProvider oProvider = new OfficeProvider(); + xMSF = (XMultiServiceFactory)oProvider.getManager(param); + + SOF = SOfficeFactory.getFactory(xMSF); + + } + catch (java.lang.Exception e) { + log.println(e.getClass().getName()); + log.println("Message: " + e.getMessage()); + failed("Cannot connect the Office."); + return false; + } + return true; + } + + /** + * This function crashes the office + */ + private void makeCrash(){ + // get all documents + Object[] allDocs = DesktopTools.getAllOpenDocuments(xMSF); + + // get one of them for dispatching + XComponent xDoc = (XComponent) allDocs[0]; + log.println("make the crash in second thread"); + + CrashThread crash = new CrashThread(xDoc, xMSF); + crash.start(); + util.utils.shortWait(); + util.utils.shortWait(); + } + + /** + * This function uses accessibility to handle the dialog which appears while the + * office is crashed. It click the button "OK" to continue. + */ + private void handleRecoveryDialogAfterCrash(int expectedDocumentCount){ + try{ + + // if the office crashes, the recovery feature needs some time + // to save all docs. Therefore the recovery dialog could need some + // time to pop up. + log.println("waiting for recovery dialog..."); + + int counter = 0; + int maximum = param.getInt(PropertyName.THREAD_TIME_OUT) / utils.DEFAULT_SHORT_WAIT_MS; + + XDialog oDialog = rt.getActiveDialog(xMSF); + + while ( oDialog == null && (counter < maximum)) + { + util.utils.shortWait(); + oDialog = rt.getActiveDialog(xMSF); + counter ++; + } + + assure("could not get Recovery Window",(oDialog != null)); + + XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, oDialog); + + UITools oUITools = new UITools(xWindow); + + oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE)); + + String[] documents = oUITools.getListBoxItems("The following files will be recovered"); + log.println("there are " + documents.length + " documents to save"); + + String msg ="The amount of documents to recover is different from the expected amount:\n"; + msg += "\texpected:\t" + expectedDocumentCount + "\n"; + msg += "\tto recover:\t" + documents.length; + + assure(msg, expectedDocumentCount == documents.length); + + log.println("disable automatically launch of Office"); + oUITools.setCheckBoxValue("Launch StarOffice automatically", Integer.valueOf(0)); + + log.println("start saving..."); + oUITools.clickButton("OK"); + + rt.waitForClosedOffice(); + + } catch (Exception e){ + e.printStackTrace(); + failed("Could not handle crash-dialog: " + e.toString()); + } + } + + private void handleCrashReporterDialog(boolean cancel){ + try{ + + log.println("try to get Crash Reporter Dialog..."); + + XDialog oDialog = rt.getActiveDialog(xMSF); + assure("could not get CrashReporter Dialog", oDialog != null); + + XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, oDialog); + + log.println(oDialog.getTitle()); + + UITools oUITools = new UITools(xWindow); + + if (cancel) { + log.println("clicking 'Cancel' button..."); + + rt.clickThreadButton(xWindow, "Cancel"); + } + else { + log.println("clicking 'Next' button..."); + oUITools.clickButton("Next>>"); + } + + } catch (Exception e){ + failed("Could not handle CrashReporter Dialog: " + e.toString()); + } + } + + private void handleRecoveryDialog_QuickExit(int expectedDocumentCount){ + log.println("handle Recovery Dialog at restart: quick exit"); + handleRecoveryDialogAtRestart(expectedDocumentCount, false, true); + handleAreYouSureDialog(true); + handleSaveDocumentsDialog(false); + + } + private void handleRecoveryDialog_QuickExitAndSave(int expectedDocumentCount){ + log.println("handle Recovery Dialog at restart: quick exit"); + handleRecoveryDialogAtRestart(expectedDocumentCount, false, true); + handleAreYouSureDialog(true); + handleSaveDocumentsDialog(true); + } + /** + * This function uses accessibility to handle the dialog which appears while the + * office is started after a crash. It waits until the "next>>" button is enabled + * and click it then to continue. + * @param expectedDocumentCount the amount of documents which must be displayed in the recovery dialog + * @param recover If the document should be recovered this variable must be true. If it is false + * the recovery process was stopped and the button cancel was clicked. + * @param cancel If the recovery is finished, this parameter decides to click the "Next" button + * or the click cancel. If the value is true, the cancel button was clicked. + */ + private void handleRecoveryDialogAtRestart(int expectedDocumentCount, boolean recover, boolean cancel){ + try{ + + log.println("try to get Recovery Dialog..."); + + XDialog oDialog = null; + oDialog = rt.getActiveDialogAfterStartup(xMSF); + + assure("could not get Recovery Dialog at start of office", (oDialog != null), ContinueWithTest.YES); + + XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, oDialog); + log.println("got the following dialog: '" +oDialog.getTitle() + "'"); + + UITools oUITools = new UITools(xWindow); + + String listBoxName = "Status of recovered documents"; + String[] documents = oUITools.getListBoxItems(listBoxName); + log.println("there are " + documents.length + " documents to recover"); + log.println("The following files will be recovered:"); + for (int i=0;i"); + + util.utils.shortWait(); + + int counter = 0; + int maximum = param.getInt(PropertyName.THREAD_TIME_OUT) / utils.DEFAULT_SHORT_WAIT_MS; + + XAccessibleContext oButton = null; + while ((oButton == null) && (counter < maximum)){ + log.println("recovering..."); + + try{ + oButton = oUITools.getButton("Next >"); + } catch (NullPointerException e){ + // no fault: The title "Start Recovery" switches to "Next" + // while all documents are recoverd + } + util.utils.shortWait(); + counter++; + } + + if (cancel) { + log.println("clicking 'Cancel' button..."); + + rt.clickThreadButton(xWindow, "Cancel"); + + } + else { + log.println("clicking 'Next' button..."); + oUITools.clickButton("Next >"); + } + + util.utils.shortWait(); + + } else { + log.println("do not recover: clicking 'Cancel' button..."); + + rt.clickThreadButton(xWindow, "Cancel"); + } + + } catch (Exception e){ + failed("Could not handle recovery-dialog at restart: " + e.toString()); + } + + } + + /** + * This function uses accessibility to handle the dialog "Are you sure". + * It click "Yes" or "No", dependent on the value of the parameter Yes + * @param yes If value is TRUE the button "Yes" was clicked, otherwise the button + * "No". + */ + private void handleAreYouSureDialog(boolean yes) + { + try{ + if (yes){ + rt.handleModalDialog(xMSF, "Yes"); + } else{ + rt.handleModalDialog(xMSF, "Cancel"); + } + } catch (com.sun.star.accessibility.IllegalAccessibleComponentStateException e){ + failed("Could not handle 'Are you sure' dialog."); + } + } + + /** + * This function uses accessibility to handle the dialog "Are you sure". + * It click "Yes" or "No", depending on the value of the parameter Yes + * @param saveDocuments If value is TRUE the button "Yes" was clicked, otherwise the button + * "No". + */ + private void handleSaveDocumentsDialog(boolean saveDocuments) + { + try{ + if (!saveDocuments){ + rt.handleModalDialog(xMSF, "Cancel"); + } else{ + XWindow oDialog = null; + oDialog = rt.getActiveWindow(xMSF); + + assure("could not get 'Save Documents' Dialog: ", (oDialog != null), ContinueWithTest.YES); + + UITools oUITools = new UITools(oDialog); + + oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE)); + + String listBoxName = "Documents"; + String[] documents = null; + try{ + documents = oUITools.getListBoxItems(listBoxName); + } catch (java.lang.Exception e){ + failed("could not get the document names from the 'Save Documents' dialog", ContinueWithTest.YES); + } + log.println("there are " + documents.length + " documents to save"); + log.println("The following documents will be saved:"); + for (int i=0;iRecoverTest. You will find here some helper + * functions. + */ +public class RecoveryTools { + + private final TestParameters param; + private final LogWriter log; + + /** + * Creates new OfficeWatcher + * @param param the test parameter + * @param log a log writer + */ + public RecoveryTools(TestParameters param, LogWriter log) { + this.param = param; + this.log = log; + + } + + /** + * get the active dialog from the top of the desktop + * @return a XDialog interface of the dialog + */ + public XDialog getActiveDialog( XMultiServiceFactory xMSF){ + XWindow xWin = getActiveWindow(xMSF); + return UnoRuntime.queryInterface(XDialog.class, xWin); + } + + public XWindow getActiveWindow( XMultiServiceFactory xMSF){ + XInterface xToolKit = null; + try { + xToolKit = (XInterface) xMSF.createInstance("com.sun.star.awt.Toolkit") ; + } catch (com.sun.star.uno.Exception e) { + return null; + } + + XExtendedToolkit tk = UnoRuntime.queryInterface(XExtendedToolkit.class, xToolKit); + Object atw = tk.getActiveTopWindow(); + return UnoRuntime.queryInterface(XWindow.class, atw); + } + + /** + * After a crash the office start with a recovery dialog. It could be that the office + * is connectable but not all services to get the dialog a loaded. This function + * tries to get the dialog until the OfficeWatcher kills the office. + * @return a XDialog interface of the dialog + */ + public XDialog getActiveDialogAfterStartup(XMultiServiceFactory xMSF){ + // while the office starts it takes some time to get the dialog. + + // the dialog is accessible AFTER the office has recoverd all documents. + // This could consumes more time then the TimeOut allow. + int counter = 0; + int multi = 5; + int pause = utils.DEFAULT_SHORT_WAIT_MS * 10; + int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5; + int maximum = (timeOut / pause) * multi; + + XDialog oDialog = getActiveDialog(xMSF); + + while (oDialog == null && (counter < maximum)){ + log.println("waiting until the office has recovered... remaining " + (timeOut * multi - pause * counter)/1000 + " seconds"); + util.utils.pause(pause); + oDialog = getActiveDialog(xMSF); + counter ++; + } + return oDialog; + } + + /** + * remove the content of the user backup folder and removes the Recovery.xcu. This + * was done from the Office via XSimpleFileAccess + * @throws com.sun.star.io.IOException the exception was thrown if something goes wrong. + */ + public void cleanRecoveryData() + throws com.sun.star.io.IOException + { + try{ + HashMap recFiles = getRecoveryFiles(); + + String recoveryFolder = recFiles.get("recoveryFolder"); + String recoveryXCU = recFiles.get("recoveryXCU"); + + log.println("try to remove content of '" + recoveryFolder + "'"); + + File rf = new File(recoveryFolder); + + boolean success = FileTools.cleanDir(rf); + log.println("removed " + recoveryFolder + ": " + success); + + log.println("try to remove '" + recoveryXCU + "'"); + + File xcu = new File(recoveryXCU); + if (xcu.isFile()){ + success = xcu.delete(); + log.println("removed " + recoveryXCU + " : " + success); + } + + } catch (Exception e){ + throw new com.sun.star.io.IOException("could not remove old recovery data", e); + } + } + + private HashMap getRecoveryFiles() + throws com.sun.star.io.IOException + { + try{ + log.println("try to get UnoProvider..."); + UnoProvider unoProv = new UnoProvider(); + XMultiServiceFactory xMSF = (XMultiServiceFactory) unoProv.getManager(param); + + String userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstraprc:UserInstallation}"); + System.out.println("userPath:'" + userPath + "'"); + + if (userPath.equals(""))userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstrap.ini:UserInstallation}"); + System.out.println("userPath:'" + userPath + "'"); + + if (userPath.equals("")) throw new com.sun.star.io.IOException("could not get user path at bootstraping"); + + String recoveryFolder = utils.getSystemURL(userPath + "/user/backup"); + + String recoveryXCU = utils.getSystemURL(userPath + "/user/registry/data/org/openoffice/Office/Recovery.xcu"); + + HashMap recFiles = new HashMap(); + + recFiles.put("recoveryFolder", recoveryFolder); + recFiles.put("recoveryXCU", recoveryXCU); + return recFiles; + + } catch (Exception e){ + throw new com.sun.star.io.IOException("could not get recovery folder", e); + } + + } + + + /** + * This function waits until the office is closed. If the closing time reach + * the value of parameter THREAD_TIME_OUT the office was killed. + */ + public void waitForClosedOffice(){ + // check for the office process + helper.ProcessHandler ph = (helper.ProcessHandler) param.get("AppProvider"); + + int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5; + int pause = utils.DEFAULT_SHORT_WAIT_MS * 20; + int multi = 0; + while ((ph != null) && (ph.getExitCode()<0) && (pause*multi < timeOut)) { + log.println("waiting until the office is closed... remaining " + (timeOut - pause * multi)/1000 + " seconds"); + util.utils.pause(pause); + multi ++; + } + + // be sure that office is closed + if (ph != null) ph.kill(); + } + + + + /** + * The office must be started WITH restore functionality. + * Therefore the parameter '--norestore' + * was removed from the AppExecutionCommand parameter + */ + public void removeParametersFromAppExecutionCommand(){ + + //remove some params to start office + String office = (String) param.get("AppExecutionCommand"); + String[] params = {"--norestore"}; + + for (int i = 0; i < params.length; i++){ + int index = office.indexOf(params[i]); + int length = params[i].length(); + if (index != -1){ + office = office.substring(0, index) + office.substring(index + length); + log.println("removed '" + params[i] + "' from AppExecutionCommand: " + office); + } + } + param.put("AppExecutionCommand", office); + log.println("connect: " + (String) param.get("AppExecutionCommand")); + + } + + /** + * This function uses accessibility to handle modal dialogs like the + * "Are you sure" dialog. + * It clicks the named button given in parameter buttonName + * @param buttonName the name of the button which should be clicked + */ + public void handleModalDialog(XMultiServiceFactory xMSF, String buttonName) + throws com.sun.star.accessibility.IllegalAccessibleComponentStateException + { + + log.println("try to get modal Dialog..."); + + util.utils.shortWait(); + + XWindow oDialog = getActiveWindow(xMSF); + + if (oDialog == null) throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("could not get modal Dialog"); + + + UITools oUITools = new UITools(oDialog); + oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE)); + + try{ + log.println("click ' " + buttonName + "' button.."); + oUITools.clickButton(buttonName); + } catch ( java.lang.Exception e){ + throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("Could not click '"+buttonName +"' at modal dialog", e); + } + util.utils.shortWait(); + } + + public void clickThreadButton(XWindow xWindow, String buttonName) + { + KlickButtonThread kbt = new KlickButtonThread(xWindow, buttonName); + kbt.start(); + util.utils.pause(utils.DEFAULT_SHORT_WAIT_MS * 10); + } + + public void copyRecoveryData(boolean backup) + throws com.sun.star.io.IOException, java.io.IOException + { + HashMap recFiles = null; + + try{ + recFiles = getRecoveryFiles(); + } catch ( com.sun.star.io.IOException e){ + throw new com.sun.star.io.IOException("Could not get recovery files", e); + } + + try{ + String recoveryFolder = recFiles.get("recoveryFolder"); + String recoveryXCU = recFiles.get("recoveryXCU"); + + File recFolder = new File(recoveryFolder); + File recFolderBackup = new File(recoveryFolder+".recoveryTest"); + + File recXCU = new File(recoveryXCU); + File recXCUBackup = new File(recoveryXCU + ".recoveryTest"); + + if (backup){ + FileTools.copyDirectory(recFolder, recFolderBackup); + FileTools.copyFile(recXCU, recXCUBackup); + } else { + FileTools.copyDirectory(recFolderBackup, recFolder); + FileTools.copyFile(recXCUBackup, recXCU); + + } + } catch (java.io.IOException e){ + // the new constructor that takes a Throwable is only available in Java1.6 + java.io.IOException newEx = new java.io.IOException("Could not copy recovery files"); + newEx.initCause(e); + throw newEx; + } + } + + +} diff --git a/framework/qa/complex/imageManager/CheckImageManager.java b/framework/qa/complex/imageManager/CheckImageManager.java new file mode 100644 index 000000000..a88a96d30 --- /dev/null +++ b/framework/qa/complex/imageManager/CheckImageManager.java @@ -0,0 +1,201 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.imageManager; + +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XInitialization; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XTypeProvider; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.ui.XImageManager; +import com.sun.star.ui.XModuleUIConfigurationManagerSupplier; +import com.sun.star.ui.XUIConfiguration; +import com.sun.star.ui.XUIConfigurationManager; +import com.sun.star.ui.XUIConfigurationPersistence; + + +// ---------- junit imports ----------------- +import lib.TestParameters; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; +import static org.junit.Assert.*; + + +/** + * + */ +public class CheckImageManager { + boolean checkUIConfigManager = false; + XMultiServiceFactory xMSF = null; + /** + * The test parameters + */ + private TestParameters param = null; + + @Before public void before() + { + xMSF = getMSF(); + param = new TestParameters(); + param.put("ServiceFactory", xMSF); // some qadevOOo functions need the ServiceFactory + } + + + @Test public void checkImageManagerFromModule() + { + System.out.println(" **** ImageManager from ModuleUIConfigurationManager *** "); + XUIConfigurationManager xManager = null; + try { + Object o = xMSF.createInstance( + "com.sun.star.ui.ModuleUIConfigurationManagerSupplier"); + XModuleUIConfigurationManagerSupplier xMUICMS = + UnoRuntime.queryInterface(XModuleUIConfigurationManagerSupplier.class, o); + xManager = xMUICMS.getUIConfigurationManager( + "com.sun.star.text.TextDocument"); + } + catch(com.sun.star.uno.Exception e) { + fail("Exception. " + e.getMessage()); + } + XImageManager xImageManager = UnoRuntime.queryInterface(XImageManager.class, xManager.getImageManager()); + performChecks(xImageManager, "ModuleUIConfig"); + } + + public void checkImageManager() { + System.out.println(" **** ImageManager from UIConfigurationManager *** "); + XUIConfigurationManager xManager = null; + try { + xManager = UnoRuntime.queryInterface(XUIConfigurationManager.class, xMSF.createInstance("com.sun.star.comp.framework.UIConfigurationManager")); + } + catch(com.sun.star.uno.Exception e) { + fail("Exception. " + e.getMessage()); + } + + XImageManager xImageManager = UnoRuntime.queryInterface(XImageManager.class, xManager.getImageManager()); + performChecks(xImageManager, "UIConfig"); + } + + private void performChecks(XImageManager xImageManager, String testObjectName) { + util.dbg.printInterfaces(xImageManager); + + OXUIConfigurationListenerImpl configListener = new OXUIConfigurationListenerImpl(); + param.put("XUIConfiguration.XUIConfigurationListenerImpl", configListener); + + XInitialization xInit = UnoRuntime.queryInterface(XInitialization.class, xImageManager); + _XInitialization _xInit = new _XInitialization(param, xInit); + assertTrue(testObjectName + "::XInitialization.initialize", _xInit._initialize()); + + // xImageManager is already there, just write a test ;-) + _XImageManager _xImage = new _XImageManager(xImageManager); + assertTrue(testObjectName + "::XImageManager.getAllImageNames", _xImage._getAllImageNames()); + assertTrue(testObjectName + "::XImageManager.getImages", _xImage._getImages()); + assertTrue(testObjectName + "::XImageManager.hasImage", _xImage._hasImage()); + assertTrue(testObjectName + "::XImageManager.insertImages", _xImage._insertImages()); + assertTrue(testObjectName + "::XImageManager.removeImages", _xImage._removeImages()); + assertTrue(testObjectName + "::XImageManager.replaceImages", _xImage._replaceImages()); + assertTrue(testObjectName + "::XImageManager.reset", _xImage._reset()); + + XTypeProvider xType = UnoRuntime.queryInterface(XTypeProvider.class, xImageManager); + _XTypeProvider _xType = new _XTypeProvider(xType); + assertTrue(testObjectName + "::XTypeProvider.getImplementationId", _xType._getImplementationId()); + assertTrue(testObjectName + "::XTypeProvider.getTypes", _xType._getTypes()); + + XUIConfiguration xUIConfig = UnoRuntime.queryInterface(XUIConfiguration.class, xImageManager); + _XUIConfiguration _xUIConfig = new _XUIConfiguration(param, xUIConfig); + _xUIConfig.before(); + assertTrue(testObjectName + "::XUIConfig.addConfigurationListener", _xUIConfig._addConfigurationListener()); + assertTrue(testObjectName + "::XUIConfig.removeConfigurationListener", _xUIConfig._removeConfigurationListener()); + + XUIConfigurationPersistence xUIConfigPersistence = (XUIConfigurationPersistence)UnoRuntime.queryInterface(XUIConfiguration.class, xImageManager); + _XUIConfigurationPersistence _xUIConfigPersistence = new _XUIConfigurationPersistence(param, xUIConfigPersistence); + _xUIConfigPersistence.before(); + assertTrue(testObjectName + "::XUIConfigPersistence.isModified", _xUIConfigPersistence._isModified()); + assertTrue(testObjectName + "::XUIConfigPersistence.isReadOnly", _xUIConfigPersistence._isReadOnly()); + assertTrue(testObjectName + "::XUIConfigPersistence.reload", _xUIConfigPersistence._reload()); + assertTrue(testObjectName + "::XUIConfigPersistence.store", _xUIConfigPersistence._store()); + assertTrue(testObjectName + "::XUIConfigPersistence.storeToStorage", _xUIConfigPersistence._storeToStorage()); + + XComponent xComp = UnoRuntime.queryInterface(XComponent.class, xImageManager); + _XComponent _xComp = new _XComponent(param, xComp); + _xComp.before(); + assertTrue(testObjectName + "::XComponent.addEventListener", _xComp._addEventListener()); + assertTrue(testObjectName + "::XComponent.removeEventListener", _xComp._removeEventListener()); + assertTrue(testObjectName + "::XComponent.dispose", _xComp._dispose()); + } + + + private static class OXUIConfigurationListenerImpl implements _XUIConfiguration.XUIConfigurationListenerImpl { + private boolean triggered = false; + + public boolean actionWasTriggered() { + return triggered; + } + + public void disposing(com.sun.star.lang.EventObject eventObject) { + triggered = true; + } + + public void elementInserted(com.sun.star.ui.ConfigurationEvent configurationEvent) { + triggered = true; + } + + public void elementRemoved(com.sun.star.ui.ConfigurationEvent configurationEvent) { + triggered = true; + } + + public void elementReplaced(com.sun.star.ui.ConfigurationEvent configurationEvent) { + triggered = true; + } + + public void fireEvent() { + // remove for real action: + triggered = !triggered; + } + + public void reset() { + // remove comment for real function + //triggered = false; + } + + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + private static final OfficeConnection connection = new OfficeConnection(); + +} diff --git a/framework/qa/complex/imageManager/_XComponent.java b/framework/qa/complex/imageManager/_XComponent.java new file mode 100644 index 000000000..0d0a997b7 --- /dev/null +++ b/framework/qa/complex/imageManager/_XComponent.java @@ -0,0 +1,167 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.imageManager; + +import com.sun.star.frame.XDesktop; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XEventListener; +import lib.TestParameters; + +/** +* Testing com.sun.star.lang.XComponent +* interface methods : +*
      +*
    • dispose()
    • +*
    • addEventListener()
    • +*
    • removeEventListener()
    • +*
    +* After this interface test object must be recreated.

    +* Multithreaded test ability not implemented yet. +* @see com.sun.star.lang.XComponent +*/ +public class _XComponent { + + private XComponent oObj = null; + private XComponent altDispose = null; + private final TestParameters tEnv; + private boolean listenerDisposed[] = new boolean[2]; + private String[] Loutput = new String[2]; + + /** + * Listener which added but not removed, and its method must be called + * on dispose call. + */ + private class MyEventListener implements XEventListener { + private final int number; + private final String message; + private MyEventListener(int number, String message) { + this.message = message; + this.number = number; + } + public void disposing ( EventObject oEvent ) { + Loutput[number] = Thread.currentThread() + " is DISPOSING " + message + this; + listenerDisposed[number] = true; + } + } + + private final XEventListener listener1 = new MyEventListener(0, "EV1"); + private final XEventListener listener2 = new MyEventListener(1, "EV2"); + + public _XComponent(TestParameters tEnv, XComponent oObj) { + this.tEnv = tEnv; + this.oObj = oObj; + } + + /** + * For the cfgmgr2.OSetElement tests: dispose the owner element. + */ + public void before() { + // do not dispose this component, but parent instead + altDispose = (XComponent)tEnv.get("XComponent.DisposeThis"); + + } + + /** + * Adds two listeners.

    + * Has OK status if then the first listener will receive an event + * on dispose method call. + */ + public boolean _addEventListener() { + + listenerDisposed[0] = false; + listenerDisposed[1] = false; + + oObj.addEventListener( listener1 ); + oObj.addEventListener( listener2 ); + + return true; + } // finished _addEventListener() + + /** + * Removes the second of two added listeners.

    + * Method tests to be completed successfully : + *

      + *
    • addEventListener : method must add two listeners.
    • + *

    + * Has OK status if no events will be sent to the second listener on + * dispose method call. + */ + public boolean _removeEventListener() { + if (disposed) + { + System.out.println("Hint: already disposed."); + return false; + } + // the second listener should not be called + oObj.removeEventListener( listener2 ); + System.out.println(Thread.currentThread() + " is removing EL " + listener2); + return true; + } // finished _removeEventListener() + + private boolean disposed = false; + + /** + * Disposes the object and then check appropriate listeners were + * called or not.

    + * Method tests to be completed successfully : + *

      + *
    • removeEventListener : method must remove one of two + * listeners.
    • + *

    + * Has OK status if liseter removed wasn't called and other listener + * was. + */ + public boolean _dispose() { + disposed = false; + + System.out.println( "begin dispose" + Thread.currentThread()); + XDesktop oDesk = (XDesktop) tEnv.get("Desktop"); + if (oDesk !=null) { + oDesk.terminate(); + } + else { + if (altDispose == null) + { + oObj.dispose(); + } + else + { + altDispose.dispose(); + } + } + + util.utils.shortWait(); + if (Loutput[0]!=null){ + System.out.println(Loutput[0]); + } + if (Loutput[1]!=null) { + System.out.println(Loutput[1]); + } + System.out.println( "end dispose" + Thread.currentThread()); + disposed = true; + + // check that dispose() works OK. + return listenerDisposed[0] && !listenerDisposed[1]; + + } // finished _dispose() + +} // finished class _XComponent + + diff --git a/framework/qa/complex/imageManager/_XImageManager.java b/framework/qa/complex/imageManager/_XImageManager.java new file mode 100644 index 000000000..c077bbf26 --- /dev/null +++ b/framework/qa/complex/imageManager/_XImageManager.java @@ -0,0 +1,105 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package complex.imageManager; + +import com.sun.star.graphic.XGraphic; +import com.sun.star.ui.ImageType; +import com.sun.star.ui.XImageManager; + + +/** + * + */ +public class _XImageManager { + + + private String[]imageNames = null; + private XGraphic[] xGraphicArray = null; + private final XImageManager oObj; + + public _XImageManager( XImageManager oObj) { + this.oObj = oObj; + } + + public boolean _getAllImageNames() { + short s = ImageType.COLOR_NORMAL + ImageType.SIZE_DEFAULT; + imageNames = oObj.getAllImageNames(s); + for (int i=0; i<(imageNames.length>10?10:imageNames.length); i++) + { + System.out.println("###### Image: " + imageNames[i]); + } + return imageNames != null; + } + + public boolean _getImages() { + short s = ImageType.COLOR_NORMAL + ImageType.SIZE_DEFAULT; + try { + xGraphicArray = oObj.getImages(s, imageNames); + } + catch(com.sun.star.lang.IllegalArgumentException e) { + } + return xGraphicArray != null; + } + + public boolean _hasImage() { + boolean result = true; + short s = ImageType.COLOR_NORMAL + ImageType.SIZE_DEFAULT; + try { // check the first image names, 10 at max + for (int i=0; i<(imageNames.length>10?10:imageNames.length); i++) + { + result &= oObj.hasImage(s, imageNames[i]); + } + } + catch(com.sun.star.lang.IllegalArgumentException e) { + result = false; + } + return result; + } + + public boolean _insertImages() { + try { + oObj.insertImages((short)imageNames.length, imageNames, xGraphicArray); + } + catch(com.sun.star.container.ElementExistException e) { + } + catch(com.sun.star.lang.IllegalArgumentException e) { + } + catch(com.sun.star.lang.IllegalAccessException e) { + } + return true; + } + + public boolean _removeImages() { + try { + oObj.removeImages((short)(imageNames.length-1), imageNames); + } + catch(com.sun.star.lang.IllegalArgumentException e) { + } + catch(com.sun.star.lang.IllegalAccessException e) { + } + return true; + } + + public boolean _replaceImages() { + return true; + } + + public boolean _reset() { + return true; + } +} diff --git a/framework/qa/complex/imageManager/_XInitialization.java b/framework/qa/complex/imageManager/_XInitialization.java new file mode 100644 index 000000000..07508ef3f --- /dev/null +++ b/framework/qa/complex/imageManager/_XInitialization.java @@ -0,0 +1,78 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.imageManager; + + + + +import com.sun.star.lang.XInitialization; +import lib.TestParameters; + +/** +* Testing com.sun.star.lang.XInitialization +* interface methods.

    +* This test needs the following object relations : +*

      +*
    • 'XInitialization.args' (of type Object[]): +* (Optional) : argument for initialize +* method. If omitted, zero length array is used.
    • +*

        +* Test is multithread compliant.

        +* Till the present time there was no need to recreate environment +* after this test completion. +*/ +public class _XInitialization { + + + private final TestParameters tEnv; + private XInitialization oObj = null; + + public _XInitialization(TestParameters tEnv, XInitialization oObj) { + + this.tEnv = tEnv; + this.oObj = oObj; + } + + /** + * Test calls the method with 0 length array and checks that + * no exceptions were thrown.

        + * Has OK status if no exceptions were thrown.

        + */ + public boolean _initialize() { + boolean result = true ; + + try { + Object[] args = (Object[]) tEnv.get("XInitialization.args"); + if (args==null) { + oObj.initialize(new Object[0]); + } else { + oObj.initialize(args); + } + + } catch (com.sun.star.uno.Exception e) { + System.out.println("Exception occurred while method calling.") ; + result = false ; + } + + return result ; + } // finished _initialize() + +} // finished class _XInitialization + + diff --git a/framework/qa/complex/imageManager/_XTypeProvider.java b/framework/qa/complex/imageManager/_XTypeProvider.java new file mode 100644 index 000000000..318c056c8 --- /dev/null +++ b/framework/qa/complex/imageManager/_XTypeProvider.java @@ -0,0 +1,89 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.imageManager; + + + +import com.sun.star.lang.XTypeProvider; +import com.sun.star.uno.Type; + +/** +* Testing com.sun.star.lang.XTypeProvider +* interface methods : +*

          +*
        • getTypes()
        • +*
        • getImplementationId()
        • +*

        +* Test is NOT multithread compliant.

        +* @see com.sun.star.lang.XTypeProvider +*/ +public class _XTypeProvider { + + + + private XTypeProvider oObj = null; + + public _XTypeProvider(XTypeProvider oObj) { + this.oObj = oObj; + } + + /** + * Just calls the method.

        + * Has OK status if no runtime exceptions occurred. + */ + public boolean _getImplementationId() { + boolean result = true; + System.out.println("testing getImplementationId() ... "); + + System.out.println("The ImplementationId is "+oObj.getImplementationId()); + result = true; + + return result; + + } // end getImplementationId() + + + /** + * Calls the method and checks the return value.

        + * Has OK status if one of the return value equals to the + * type com.sun.star.lang.XTypeProvider. + */ + public boolean _getTypes() { + boolean result = false; + System.out.println("getting Types..."); + Type[] types = oObj.getTypes(); + for (int i=0;i"); + } + + return result; + + } // end getTypes() + +} + diff --git a/framework/qa/complex/imageManager/_XUIConfiguration.java b/framework/qa/complex/imageManager/_XUIConfiguration.java new file mode 100644 index 000000000..f2e7be33d --- /dev/null +++ b/framework/qa/complex/imageManager/_XUIConfiguration.java @@ -0,0 +1,66 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.imageManager; + + +import com.sun.star.ui.XUIConfiguration; +import com.sun.star.ui.XUIConfigurationListener; +import lib.TestParameters; + + + +public class _XUIConfiguration { + + + private final TestParameters tEnv; + private final XUIConfiguration oObj; + private XUIConfigurationListenerImpl xListener = null; + + public interface XUIConfigurationListenerImpl + extends XUIConfigurationListener { + void reset(); + void fireEvent(); + boolean actionWasTriggered(); + } + + + public _XUIConfiguration(TestParameters tEnv, XUIConfiguration oObj) { + this.tEnv = tEnv; + this.oObj = oObj; + } + + public void before() { + xListener = (XUIConfigurationListenerImpl)tEnv.get( + "XUIConfiguration.XUIConfigurationListenerImpl"); + } + + public boolean _addConfigurationListener() { + oObj.addConfigurationListener(xListener); + xListener.fireEvent(); + return xListener.actionWasTriggered(); + } + + public boolean _removeConfigurationListener() { + oObj.removeConfigurationListener(xListener); + xListener.reset(); + xListener.fireEvent(); + return !xListener.actionWasTriggered(); + } + +} diff --git a/framework/qa/complex/imageManager/_XUIConfigurationPersistence.java b/framework/qa/complex/imageManager/_XUIConfigurationPersistence.java new file mode 100644 index 000000000..23735a179 --- /dev/null +++ b/framework/qa/complex/imageManager/_XUIConfigurationPersistence.java @@ -0,0 +1,84 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package complex.imageManager; + +import com.sun.star.embed.XStorage; +import com.sun.star.ui.XUIConfigurationPersistence; +import lib.TestParameters; + + + +public class _XUIConfigurationPersistence { + + + private final TestParameters tEnv; + private final XUIConfigurationPersistence oObj; + private XStorage xStore = null; + + public _XUIConfigurationPersistence(TestParameters tEnv, XUIConfigurationPersistence oObj) { + + this.tEnv = tEnv; + this.oObj = oObj; + } + + public void before() { + xStore = (XStorage)tEnv.get("XUIConfigurationStorage.Storage"); + } + + public boolean _reload() { + try { + oObj.reload(); + } + catch(com.sun.star.uno.Exception e) { + + } + return true; + } + + public boolean _store() { + try { + oObj.store(); + } + catch(com.sun.star.uno.Exception e) { + + } + return true; + } + + public boolean _storeToStorage() { + boolean result = true; + try { + oObj.storeToStorage(xStore); + } + catch(com.sun.star.uno.Exception e) { + result = false; + + } + return result; + } + + public boolean _isModified() { + return !oObj.isModified(); + } + + public boolean _isReadOnly() { + return !oObj.isReadOnly(); + } + +} diff --git a/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java new file mode 100644 index 000000000..451ba1292 --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java @@ -0,0 +1,526 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + + package complex.loadAllDocuments; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import helper.URLHelper; + +import java.io.File; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; +import org.openoffice.test.OfficeFileUrl; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.frame.FrameSearchFlag; +import com.sun.star.frame.XComponentLoader; +import com.sun.star.frame.XFrame; +import com.sun.star.frame.XStorable; +import com.sun.star.io.XInputStream; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.ucb.XSimpleFileAccess; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.XCloseable; + + +/** @short Check the interface method XComponentLoader.loadComponentFromURL() + + @descr A prerequisite for this test is a server which allows access to files + that will be loaded via three different access methods: +

          +
        • 1. nfs (mounted directory / mapped network drive)
        • +
        • 2. ftp
        • +
        • 3. http
        • +
        +

        + The test will look for a list of files from the TestDocumentPath + on and load these files from the mounted directory, via ftp and http. + The parameters for this have to be "ftp_access" and "http_access". + If they are not given, tests for ftp and http will fail. + + @todo We need a further test for accessing UNC paths on windows! + */ +public class CheckXComponentLoader +{ + + // some const + + /** used to classify the result of a loadComponentFromURL() request. */ + private static final int RESULT_VALID_DOC = 1; + private static final int RESULT_EMPTY_DOC = 2; + private static final int RESULT_ILLEGALARGUMENTEXCEPTION = 3; + private static final int RESULT_IOEXCEPTION = 4; + private static final int RESULT_RUNTIMEEXCEPTION = 5; + private static final int RESULT_EXCEPTION = 6; + + /** used for testing password protected files. */ + private static final String SUFFIX_PASSWORD_TEMPFILE = "password_"; + private static final String PREFIX_PASSWORD_TEMPFILE = ".sxw"; + private static final String DEFAULT_PASSWORD = "DefaultPasswordForComponentLoaderTest"; + + + // member + + /** provides XComponentLoader interface too. */ + private XFrame m_xFrame = null; + + /** will be set to xDesktop OR xFrame. */ + private XComponentLoader m_xLoader = null; + + /** can be used to open local files as stream. */ + private XSimpleFileAccess m_xStreamProvider = null; + + /** directory for creating temp. files. */ + private String m_sTempPath = null; + + /** directory for searching files to load */ + private String m_sTestDocPath = null; + + /** files of m_sTestDocPath to test. */ + private static ArrayList m_lTestFiles = null; + + + // test environment + + + /** @short Create the environment for following tests. + + @descr Use either a component loader from desktop or + from frame + */ + @Before public void before() throws Exception + { + // get uno service manager from global test environment + /* points to the global uno service manager. */ + XMultiServiceFactory xMSF = getMSF(); + + // create stream provider + m_xStreamProvider = UnoRuntime.queryInterface(XSimpleFileAccess.class, xMSF.createInstance("com.sun.star.ucb.SimpleFileAccess")); + + // create desktop instance + /* provides XComponentLoader interface. */ + XFrame xDesktop = UnoRuntime.queryInterface(XFrame.class, xMSF.createInstance("com.sun.star.frame.Desktop")); + + // create frame instance + m_xFrame = xDesktop.findFrame("testFrame_componentLoader", + FrameSearchFlag.TASKS | FrameSearchFlag.CREATE); + assertNotNull("Couldn't create test frame.", m_xFrame); + + // define default loader for testing + // TODO think about using of bot loader instances! + m_xLoader = UnoRuntime.queryInterface(XComponentLoader.class, xDesktop); + assertNotNull("Desktop service doesn't support needed component loader interface.", m_xLoader); + + // get temp path for this environment + final String tempDirURL = util.utils.getOfficeTemp/*Dir*/(getMSF()); + m_sTempPath = graphical.FileHelper.getSystemPathFromFileURL(tempDirURL); + // m_sTempPath = "."+fs_sys; + + // get all files from the given directory + // TODO URLHelper should ignore directories! + m_lTestFiles = new ArrayList(); + final String sTestDocURL = OfficeFileUrl.getAbsolute(new File("testdocuments")); + m_sTestDocPath = graphical.FileHelper.getSystemPathFromFileURL(sTestDocURL); + File aBaseDir = new File(m_sTestDocPath); + List lDirContent = URLHelper.getSystemFilesFromDir(aBaseDir.getPath()); + Iterator lList = lDirContent.iterator(); + int nBasePathLength = m_sTestDocPath.length(); + while(lList.hasNext()) + { + File aFile = lList.next(); + + // ignore broken links and directories at all + if ( + (!aFile.exists()) || + (!aFile.isFile()) + ) + { + continue; + } + + String sCompletePath = aFile.getAbsolutePath(); + String sSubPath = sCompletePath.substring(nBasePathLength); + + m_lTestFiles.add(sSubPath); + } + } + + + /** @short close the environment. + */ + @After public void after() throws Exception + { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, m_xFrame); + xClose.close(false); + + m_xFrame = null; + m_xLoader = null; + } + + + /** @short Look for files in the given directory for loading. + */ + @Test public void checkUsingOfMediaDescriptor() + { + InteractionHandler xHandler = new InteractionHandler(); + StatusIndicator xIndicator = new StatusIndicator(); + + PropertyValue[] lProps = new PropertyValue[3]; + + lProps[0] = new PropertyValue(); + lProps[0].Name = "Hidden"; + lProps[0].Value = Boolean.TRUE; + + lProps[1] = new PropertyValue(); + lProps[1].Name = "InteractionHandler"; + lProps[1].Value = xHandler; + + lProps[2] = new PropertyValue(); + lProps[2].Name = "StatusIndicator"; + lProps[2].Value = xIndicator; + + Iterator aSnapshot = m_lTestFiles.iterator(); + while (aSnapshot.hasNext()) + { + File aSysFile = new File(m_sTestDocPath, aSnapshot.next()); + String sURL = URLHelper.getFileURLFromSystemPath(aSysFile); + + loadURL(m_xLoader, RESULT_VALID_DOC, sURL, "_blank", 0, lProps); + // It's not needed to reset this using states! + // It's done internally... + if (!xIndicator.wasUsed()) + { + System.out.println("External progress was not used for loading."); + } + if (xHandler.wasUsed()) + { + System.out.println("External interaction handler was not used for loading."); + } + } + } + + + /** TODO document me and move this method to a more global helper! */ + private String impl_getTempFileName(String sTempPath, + String sSuffix , + String sPrefix ) + { + File aDir = new File(sTempPath); + aDir.mkdirs(); + + // TODO: create a temp file which not exist! + for (int i=0; i<999999; ++i) + { + File aTempFile = new File(aDir, sSuffix+i+sPrefix); + if (!aTempFile.exists()) + { + return aTempFile.getAbsolutePath(); + } + } + + fail("Seems that all temp file names are currently in use!"); + return null; + } + + + /** TODO document me and move this method to a more global helper! */ + private void impl_createTempOfficeDocument(XComponentLoader xLoader , + String sSourceURL, + String sTargetURL, + String sFilter , + String sPassword ) throws Exception + { + PropertyValue[] lLoadProps = new PropertyValue[1]; + + lLoadProps[0] = new PropertyValue(); + lLoadProps[0].Name = "Hidden"; + lLoadProps[0].Value = Boolean.TRUE; + + PropertyValue[] lSaveProps = new PropertyValue[3]; + + lSaveProps[0] = new PropertyValue(); + lSaveProps[0].Name = "FilterName"; + lSaveProps[0].Value = sFilter; + + lSaveProps[1] = new PropertyValue(); + lSaveProps[1].Name = "PassWord"; + lSaveProps[1].Value = sPassword; + + lSaveProps[2] = new PropertyValue(); + lSaveProps[2].Name = "Overwrite"; + lSaveProps[2].Value = Boolean.TRUE; + + XComponent xDoc = null; + // load it + xDoc = xLoader.loadComponentFromURL(sSourceURL, "_blank", 0, lLoadProps); + assertNotNull("Could create office document, which should be saved as temp one.", xDoc); + + // save it as temp file + XStorable xStore = UnoRuntime.queryInterface(XStorable.class, xDoc); + xStore.storeAsURL(sTargetURL, lSaveProps); + + // Don't forget to close this file. Otherwise the temp file is locked! + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xDoc); + xClose.close(false); + } + + + /** @short Check the password handling. + + @descr The used password is the one given + as password for the ftp connection, + or - if none given a default one. + */ + @Test public void checkLoadingWithPassword() throws Exception + { + String sTempFile = impl_getTempFileName(m_sTempPath, SUFFIX_PASSWORD_TEMPFILE, PREFIX_PASSWORD_TEMPFILE); + File aTestFile = new File(sTempFile); + String sTestURL = URLHelper.getFileURLFromSystemPath(aTestFile); + + impl_createTempOfficeDocument(m_xLoader, "private:factory/swriter", sTestURL, "StarOffice XML (Writer)", DEFAULT_PASSWORD); + + PropertyValue[] lArgs1 = new PropertyValue[2]; + + lArgs1[0] = new PropertyValue(); + lArgs1[0].Name = "Hidden"; + lArgs1[0].Value = Boolean.TRUE; + + lArgs1[1] = new PropertyValue(); + lArgs1[1].Name = "Password"; + lArgs1[1].Value = DEFAULT_PASSWORD; + + PropertyValue[] lArgs2 = new PropertyValue[1]; + + lArgs2[0] = new PropertyValue(); + lArgs2[0].Name = "Hidden"; + lArgs2[0].Value = Boolean.TRUE; + + loadURL(m_xLoader, RESULT_VALID_DOC, sTestURL, "_blank", 0, lArgs1); +// TODO: wrong? loadURL(m_xLoader, RESULT_EMPTY_DOC, sTestURL, "_blank", 0, lArgs2); + } + + /** + * Check URL encoding. The first filename that matches "*.sxw" + * is used as source for several encodings. + */ + @Test public void checkURLEncoding() throws Exception { + PropertyValue[] lProps = new PropertyValue[1]; + + lProps[0] = new PropertyValue(); + lProps[0].Name = "Hidden"; + lProps[0].Value = Boolean.TRUE; + + // first get encoding of this system + InputStreamReader in = new InputStreamReader(System.in); + String sSystemEncoding = in.getEncoding(); + + System.out.println("This system's encoding: " + sSystemEncoding); + + assertNotNull("Found an empty directory. There are no files for testing.", m_lTestFiles); + + + // get a file name as byte array + Iterator aSnapshot = m_lTestFiles.iterator(); + byte[] baURL = null; + + while (aSnapshot.hasNext()) { + File aFile = new File(m_sTestDocPath, aSnapshot.next()); + String sFile = URLHelper.getFileURLFromSystemPath(aFile); + + // take the first sxw file as stream + if (sFile.endsWith(".sxw")) { + baURL = sFile.getBytes(); + + break; + } + } + + assertNotNull("Found no file to load. Cannot test.", baURL); + + //construct several different encoded strings + String[] sEncoding = new String[] { + "US-ASCII", "TRUE", // us ascii encoding + "ISO-8859-1", "TRUE", // iso encoding + "UTF-8", "TRUE", // 8 bit utf encoding + "UTF-16BE", "FALSE", // 16 bit big endian utf + "UTF-16LE", "FALSE", // 16 bit little endian utf + "UTF-16", "FALSE" // 16 bit, order specified by byte order mark + + }; + + for (int i = 0; i < sEncoding.length; i = i + 2) { + String encURL = new String(baURL, sEncoding[i]); + System.out.println("ENC[" + sEncoding[i] + "]"); + + if (sEncoding[i + 1].equals("TRUE")) { + loadURL(m_xLoader, RESULT_VALID_DOC, encURL, "_blank", 0, + lProps); + } else { + //with cws_loadenv01 changed to IllegalArgumentException + loadURL(m_xLoader, RESULT_ILLEGALARGUMENTEXCEPTION, encURL, "_blank", 0, + lProps); + } + } + } + + /** TODO document me + */ + @Test public void checkStreamLoading() throws Exception + { + PropertyValue[] lProps = new PropertyValue[2]; + + lProps[0] = new PropertyValue(); + lProps[0].Name = "Hidden"; + lProps[0].Value = Boolean.TRUE; + + lProps[1] = new PropertyValue(); + lProps[1].Name = "InputStream"; + + Iterator aSnapshot = m_lTestFiles.iterator(); + while (aSnapshot.hasNext()) + { + File aFile = new File(m_sTestDocPath, aSnapshot.next()); + String sURL = URLHelper.getFileURLFromSystemPath(aFile); + + XInputStream xStream = m_xStreamProvider.openFileRead(sURL); + lProps[1].Value = xStream; + + // check different version of "private:stream" URL! + loadURL(m_xLoader, RESULT_VALID_DOC, "private:stream" , "_blank", 0, lProps); + } + } + + /** + * Loads one URL with the given parameters using the method + * loadComponentFromURL(). Further it's possible to specify, which result is + * required and we check internally if it was reached. Logging of errors + * and success stories is done inside this method too. Of course we catch + * all possible exceptions and try to leave the office without any forgotten + * but opened documents. + */ + private void loadURL(XComponentLoader xLoader, int nRequiredResult, + String sURL, String sTarget, int nFlags, + PropertyValue[] lProps) { + int nResult = RESULT_EMPTY_DOC; + XComponent xDoc = null; + + try { + xDoc = xLoader.loadComponentFromURL(sURL, sTarget, nFlags, + lProps); + + if (xDoc != null) { + nResult = RESULT_VALID_DOC; + } else { + nResult = RESULT_EMPTY_DOC; + } + } catch (com.sun.star.lang.IllegalArgumentException exArgument) { + nResult = RESULT_ILLEGALARGUMENTEXCEPTION; + } catch (com.sun.star.io.IOException exIO) { + nResult = RESULT_IOEXCEPTION; + } catch (com.sun.star.uno.RuntimeException exRuntime) { + nResult = RESULT_RUNTIMEEXCEPTION; + } catch (Exception e) { + nResult = RESULT_EXCEPTION; + } + + try { + if (xDoc != null) { + xDoc.dispose(); + xDoc = null; + } + } catch (com.sun.star.uno.RuntimeException exClosing) { + System.out.println("exception during disposing of a document found!" + + " Doesn't influence test - but should be checked."); + } + + String sMessage = "URL[\"" + sURL + "\"]"; + + if (nResult == nRequiredResult) { + System.out.println(sMessage + " expected result [" + + convertResult2String(nResult) + "] "); + } else { + fail(sMessage + " unexpected result [" + + convertResult2String(nResult) + "] " + + "\nrequired was [" + + convertResult2String(nRequiredResult) + "]" + + "\nwe got [" + convertResult2String(nResult) + "]" + ); + } + } + + /** + * it match the int result value to a string, which can be used for logging + */ + private static String convertResult2String(int nResult) { + switch (nResult) { + case RESULT_VALID_DOC: + return "VALID_DOC"; + + case RESULT_EMPTY_DOC: + return "EMPTY_DOC"; + + case RESULT_ILLEGALARGUMENTEXCEPTION: + return "ILLEGALARGUMENTEXCEPTION"; + + case RESULT_IOEXCEPTION: + return "IOEXCEPTION"; + + case RESULT_RUNTIMEEXCEPTION: + return "RUNTIMEEXCEPTION"; + + case RESULT_EXCEPTION: + return "ALLOTHEREXCEPTION"; + } + + return "unknown!"; + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + private static final OfficeConnection connection = new OfficeConnection(); + +} diff --git a/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props new file mode 100644 index 000000000..92b56bef9 --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props @@ -0,0 +1 @@ +ThreadTimeOut=600000 diff --git a/framework/qa/complex/loadAllDocuments/InteractionHandler.java b/framework/qa/complex/loadAllDocuments/InteractionHandler.java new file mode 100644 index 000000000..24cf6a151 --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/InteractionHandler.java @@ -0,0 +1,122 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package complex.loadAllDocuments; + +import com.sun.star.task.XInteractionHandler; +import com.sun.star.uno.AnyConverter; + + +/** + * Implements a simple interaction handler, + * which can abort all incoming interactions only ... but make it possible to + * log it. So it can be used for debug and test purposes. + */ +public class InteractionHandler implements XInteractionHandler +{ + + + /** + * @const RETRY_COUNT it defines the max count of + * retrying of an interaction + */ + private static final int RETRY_COUNT = 3; + + + + /** + * count using of RETRY continuations + */ + private int m_nTry ; + /** true if the interaction handler was used */ + private boolean m_bWasUsed ; + + + /** + * ctor + * It's initialize an object of this class with default values + * and set the protocol stack. So the outside code can check + * if this handler was used or not. + */ + public InteractionHandler() + { + m_nTry = 0 ; + m_bWasUsed = false; + } + + /** + * Called to start the interaction, because the outside code wish to solve + * a detected problem or to inform the user about something. + * We save the information here and can handle two well known continuations + * only. + * [abort and retry]. + * + * @param xRequest + * describe the interaction + */ + public void handle(com.sun.star.task.XInteractionRequest xRequest) + { + m_bWasUsed = true; + + // analyze the possible continuations. + // We can abort all incoming interactions only. + // But additional we can try to continue it several times too. + // Of course after e.g. three loops we have to stop and abort it. + com.sun.star.task.XInteractionContinuation[] lContinuations = xRequest.getContinuations(); + + com.sun.star.task.XInteractionAbort xAbort = null; + com.sun.star.task.XInteractionRetry xRetry = null; + com.sun.star.uno.Type xAbortType = new com.sun.star.uno.Type(com.sun.star.task.XInteractionAbort.class); + com.sun.star.uno.Type xRetryType = new com.sun.star.uno.Type(com.sun.star.task.XInteractionRetry.class); + + for (int i=0; i aListOfWorkingProperty; + + /** + * Initialize before the tests start: this has to be done only once. + * This methods sets the 'aPathSettings' and 'xPropertyInfoOfPathSettings' variables. + */ + @Before + public void before() throws Exception + { + try + { + aPathSettings = thePathSettings.get(connection.getComponentContext()); + assertNotNull("Can't instantiate com.sun.star.util.thePathSettings.", aPathSettings); + util.dbg.getSuppServices(aPathSettings); + final XPropertySet xPropSet_of_PathSettings = UnoRuntime.queryInterface(XPropertySet.class, aPathSettings); + + xPropertyInfoOfPathSettings = xPropSet_of_PathSettings.getPropertySetInfo().getProperties(); + aPathSettingNames = new String[xPropertyInfoOfPathSettings.length]; + aPathSettingValues = new String[xPropertyInfoOfPathSettings.length]; + + aListOfWorkingProperty = new ArrayList(); + + // get initial values and create new ones + for (int i = 0; i < xPropertyInfoOfPathSettings.length; i++) + { + final String sName = xPropertyInfoOfPathSettings[i].Name; + aPathSettingNames[i] = sName; + Object o = xPropSet_of_PathSettings.getPropertyValue(sName); + + String sValue = convertToString(o); + aPathSettingValues[i] = sValue; + aListOfWorkingProperty.add(xPropertyInfoOfPathSettings[i]); + } + } + catch (com.sun.star.uno.Exception e) + { + System.out.println(e.getClass().getName()); + System.out.println("Message: " + e.getMessage()); + } + } + + private String convertToString(Object o) + { + String sValue = ""; + try + { + if (AnyConverter.isString(o)) + { + sValue = AnyConverter.toString(o); + } + else if (AnyConverter.isArray(o)) + { + Object oValueList = AnyConverter.toArray(o); + String[] aValueList = (String[]) oValueList; + String sValues = ""; + for (int j = 0; j < aValueList.length; j++) + { + if (sValues.length() > 0) + { + sValues += ";"; + } + sValues += aValueList[j]; + } + sValue = sValues; + } + else + { + System.out.println("Can't convert Object to String"); + } + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + /* ignore */ + } + return sValue; + } + + /** + * Simple existence test, if this fails, the Lists must update + */ + @Test + public void checkInternalListConsistence() + { + // check if all Properties are in the internal test list + for (int i = 0; i < xPropertyInfoOfPathSettings.length; i++) + { + final String sName = xPropertyInfoOfPathSettings[i].Name; + boolean bOccur = checkIfNameExistsInList(sName, availablePropNames, availablePropNameExtensions); + assertTrue("TEST IS WRONG, Name:='" + sName + "' doesn't exist in internal Test list.", bOccur); + } + + // check if all properties in the internal list also exist in real life + for (int i = 0; i < availablePropNames.length; i++) + { + final String aListName = availablePropNames[i]; + for (int j = 0; j < availablePropNameExtensions.length; j++) + { + final String aSubListName = availablePropNameExtensions[j]; + final String aName = aListName + aSubListName; + boolean bOccur = checkIfNameExistsInList(aName, aPathSettingNames, new String[] + { + "" + } /* list must not empty! */); + assertTrue("TEST IS WRONG, Name:='" + aName + "' from the internal test list do not occur in real life path settings.", bOccur); + } + } + } + + /** + * Simple O(n^n) check if a given String (_sNameMustOccur) exist in the given list(+SubList) values. + * @param _sNameMustOccur + * @param _aList + * @param _aSubList + * @return true, if name occur + */ + private boolean checkIfNameExistsInList(String _sNameMustOccur, String[] _aList, String[] _aSubList) + { + for (int i = 0; i < _aList.length; i++) + { + final String aListName = _aList[i]; + for (int j = 0; j < _aSubList.length; j++) + { + final String aSubListName = _aSubList[j]; + final String aName = aListName + aSubListName; + if (aName.equals(_sNameMustOccur)) + { + return true; + } + } + } + return false; + } + + /** + * Shows the path settings + */ + @Test + public void showPathSettings() throws UnknownPropertyException, WrappedTargetException + { + System.out.println("\n---- All properties ----"); + final XPropertySet xPropSet_of_PathSettings = UnoRuntime.queryInterface(XPropertySet.class, aPathSettings); + + for (int i = 0; i < aListOfWorkingProperty.size(); i++) + { + final String sName = aListOfWorkingProperty.get(i).Name; + System.out.print(sName); + Object o = xPropSet_of_PathSettings.getPropertyValue(sName); + + try + { + AnyConverter.toString(o); + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + } + System.out.println(); + } + System.out.println("---- Finish showing properties ----\n"); + } + + private boolean checkPaths(Object _o, Object _o2) + { + String sLeftPath = ""; + String sRightPath = ""; + if (AnyConverter.isArray(_o)) + { + try + { + Object oValues = AnyConverter.toArray(_o); + sLeftPath = convertToString(oValues); + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + } + } + else if (AnyConverter.isString(_o)) + { + try + { + sLeftPath = AnyConverter.toString(_o); + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + } + } + + if (AnyConverter.isArray(_o2)) + { + try + { + Object oValues = AnyConverter.toArray(_o2); + sRightPath = convertToString(oValues); + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + } + } + else if (AnyConverter.isString(_o2)) + { + try + { + sRightPath = AnyConverter.toString(_o2); + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + } + } + return checkPaths(sLeftPath, sRightPath); + } + + /** + * Check 2 given paths if the _aOtherPath exists in _aPath, _aPath could be a list separated by ';' + * @param _aPath + * @param _aOtherPath + * @return true, if _aOtherPath found + */ + private boolean checkPaths(String _aPath, String _aOtherPath) + { + if (_aOtherPath.contains(";")) + { + StringTokenizer aToken = new StringTokenizer(_aOtherPath, ";"); + int nCount = 0; + int nFound = 0; + while (aToken.hasMoreElements()) + { + String sPath = (String)aToken.nextElement(); + nCount ++; + if (checkPaths(_aPath, sPath)) + { + nFound++; + } + } + if (nFound == nCount) + { + return true; + } + } + else if(_aPath.contains(";")) + { + StringTokenizer aToken = new StringTokenizer(_aPath, ";"); + while (aToken.hasMoreElements()) + { + String sToken = (String)aToken.nextElement(); + if (sToken.equals(_aOtherPath)) + { + return true; + } + } + return false; + } + else if (_aPath.equals(_aOtherPath)) + { + return true; + } + return false; + } + + /** + * This tests the XFastPropertySet interface implementation. + */ + @Test + public void checkXFastPropertySet() + { + System.out.println("---- Testing the XFastPropertySet interface ----"); + + + // do for all properties + // xPropertyInfoOfPathSettings.length + for (int i = 0; i < aListOfWorkingProperty.size(); i++) + { + final Property property = aListOfWorkingProperty.get(i); // xPropertyInfoOfPathSettings[i]; + String name = property.Name; + // get property name and initial value + System.out.println("Test property with name: " + name); + boolean bResult; + if (name.endsWith("_writable")) + { + bResult = checkStringProperty(property); + } + else if (name.endsWith("_user")) + { + bResult = checkStringListProperty(property); + } + else if (name.endsWith("_internal")) + { + bResult = checkStringListProperty(property); + } + else + { + // old path settings + bResult = checkStringProperty(property); + } + System.out.print(" Test of property " + name + " finished"); + if (bResult) + { + System.out.println(" [ok]"); + } + else + { + System.out.println(" [FAILED]"); + } + System.out.println(); + } + System.out.println("---- Test of XFastPropertySet finished ----\n"); + } + + private boolean checkStringListProperty(Property property) + { + // creating instances + boolean bResult = true; + XFastPropertySet xFPS = UnoRuntime.queryInterface(XFastPropertySet.class, aPathSettings); + + String name = property.Name; + int handle = property.Handle; + + Object oValue; + try + { + oValue = xFPS.getFastPropertyValue(handle); + } + catch (UnknownPropertyException ex) + { + return false; + } + catch (WrappedTargetException ex) + { + return false; + } + + if (!AnyConverter.isArray(oValue)) + { + System.out.println(" Internal error, type wrong. PathSetting property with name:" + name + " should be an array."); + return false; + } + + String val; + try + { + Object oValues = AnyConverter.toArray(oValue); + + + final String[] aValues = (String[])oValues; + + // aNewValues contains a deep copy of aValues + String[] aNewValues = new String[aValues.length]; + System.arraycopy(aValues, 0, aNewValues, 0, aValues.length); + if (aValues.length > 0) + { + val = aValues[0]; + } + else + { + val = null; + aNewValues = new String[1]; // create a String list + } + System.out.println(" Property has initial value: '" + val + "'"); + + // set to a new correct value + String newVal = changeToCorrectValue(val); + assertFalse("newVal must not equal val.", newVal.equals(val)); + + System.out.println(" Try to change to a correct value '" + newVal + "'"); + aNewValues[0] = newVal; + + try + { + try + { + xFPS.setFastPropertyValue(handle, aNewValues); + } + catch (com.sun.star.lang.WrappedTargetException e) + { + System.out.println(" FAIL: setFastPropertyValue(handle:=" + handle + ", name:='" + name + "')" + e.getMessage()); + bResult = false; + } + + // Property_internal can't change we will not arrive beyond this line + + // check the change + Object oObj = xFPS.getFastPropertyValue(handle); + if (!checkPaths(oObj, aNewValues)) + { + System.out.println(" FAIL: Did not change value on property " + name + "."); + bResult = false; + } + + // set back to initial setting + System.out.println(" Try to check"); + try + { + xFPS.setFastPropertyValue(handle, oValue); + } + catch (com.sun.star.beans.PropertyVetoException e) + { + // should not occur + System.out.println(" FAIL: PropertyVetoException caught: " + e.getMessage()); + bResult = false; + } + } + catch (com.sun.star.beans.PropertyVetoException e) + { + if (!name.endsWith("_internal")) + { + // should not occur + System.out.println(" FAIL: PropertyVetoException caught: " + e.getMessage()); + bResult = false; + } + else + { + System.out.println(" OK: PropertyVetoException caught: " + e.getMessage() + " it seems not allowed to change internal values."); + } + } + + // check if changed + Object checkVal3 = xFPS.getFastPropertyValue(handle); + if (!checkPaths(checkVal3, oValues)) + { + System.out.println(" FAIL: Can't change value back to original on property " + name); + bResult = false; + } + } + catch (com.sun.star.uno.Exception e) + { + System.out.println(" FAIL: getFastPropertyValue(handle:=" + handle + ", name:='" + name + "')" + e.getMessage()); + bResult = false; + } + return bResult; + } + + private boolean checkStringProperty(Property property) + { + boolean bResult = true; + XFastPropertySet xFPS = UnoRuntime.queryInterface(XFastPropertySet.class, aPathSettings); + String name = property.Name; + int handle = property.Handle; + Object oValue; + try + { + oValue = xFPS.getFastPropertyValue(handle); + } + catch (UnknownPropertyException ex) + { + return false; + } + catch (WrappedTargetException ex) + { + return false; + } + + + try + { + String val = ""; + val = AnyConverter.toString(oValue); + System.out.println(" Property has initial value: '" + val + "'"); + + // set to a new correct value + String newVal = changeToCorrectValue(val); + System.out.println(" Try to change to a correct value '" + newVal + "'"); + xFPS.setFastPropertyValue(handle, newVal); + + // check the change + String checkVal = (String) xFPS.getFastPropertyValue(handle); + if (!checkPaths(checkVal, newVal)) + { + System.out.println(" FAIL: Did not change value on property " + name + "."); + bResult = false; + } + /* + * Change the given String to an incorrect path URL. + */ + newVal = "fileblablabla"; + System.out.println(" Try to change to incorrect value '" + newVal + "'"); + try + { + xFPS.setFastPropertyValue(handle, newVal); + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + System.out.println(" Correctly thrown Exception caught."); + } + + // check if changed + String checkVal2 = (String) xFPS.getFastPropertyValue(handle); + if (!checkPaths(checkVal2, checkVal)) + { + System.out.println(" FAIL: Value did change on property " + name + " though it should not have."); + bResult = false; + } + else + { + System.out.println(" OK: Incorrect value was not set."); + } + // set back to initial setting + System.out.println(" Set back to initial value."); + try + { + xFPS.setFastPropertyValue(handle, val); + } + catch (com.sun.star.lang.IllegalArgumentException e) + { + System.out.println(" IllegalArgumentException caught: " + e.getMessage()); + bResult = false; + } + // check if changed + String checkVal3 = (String) xFPS.getFastPropertyValue(handle); + if (!checkVal3.equals(val)) + { + if (!checkPaths(checkVal3, val)) + { + System.out.println(" FAIL: Can't change value back to original on property " + name); + System.out.println(" Value is: " + checkVal3); + + bResult = false; + } + else + { + System.out.println(" OK: the pathsettings contains the original path."); + System.out.println(" Value is: " + checkVal3); + System.out.println(" Value should be: " + val); + } + } + else + { + System.out.println(" OK: Change value back to original on property " + name); + } + } + catch (com.sun.star.uno.Exception e) + { + System.out.println(" FAIL: getFastPropertyValue(handle:=" + handle + ", name:='" + name + "')" + e.getMessage()); + bResult = false; + } + return bResult; + } + + + // ____________________ + /** + * This tests the XPropertySet interface implementation. + */ + + /** + * Change the given String to a correct path URL. + * @return The changed path URL. + */ + private String changeToCorrectValue(String path) + { + // the simplest possibility + if (path == null || path.equals("")) + { + String sTempDir = System.getProperty("java.io.tmpdir"); + sTempDir = util.utils.getFullURL(sTempDir); + return sTempDir; // "file:///tmp"; + } + return graphical.FileHelper.appendPath(path, "tmp"); + } + + /** + * Listener implementation which sets a flag when + * listener was called. + */ + public class MyChangeListener implements XPropertiesChangeListener, + XPropertyChangeListener, + XVetoableChangeListener + { + + private boolean propChanged = false; + private boolean propertiesChanged = false; + private boolean vetoableChanged = false; + + public void propertiesChange( + com.sun.star.beans.PropertyChangeEvent[] e) + { + propertiesChanged = true; + } + + public void vetoableChange(com.sun.star.beans.PropertyChangeEvent pE) + throws com.sun.star.beans.PropertyVetoException + { + vetoableChanged = true; + } + + public void propertyChange(com.sun.star.beans.PropertyChangeEvent pE) + { + propChanged = true; + } + + public void disposing(com.sun.star.lang.EventObject eventObject) + { + } + + public void resetListener() + { + propChanged = false; + propertiesChanged = false; + vetoableChanged = false; + } + + public boolean changePropertyEventFired() + { + return propChanged; + } + + public boolean changePropertiesEventFired() + { + return propertiesChanged; + } + + public boolean vetoableChangeEventFired() + { + return vetoableChanged; + } + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + private static final OfficeConnection connection = new OfficeConnection(); +} diff --git a/framework/qa/complex/path_substitution/PathSubstitutionTest.java b/framework/qa/complex/path_substitution/PathSubstitutionTest.java new file mode 100644 index 000000000..96d59287c --- /dev/null +++ b/framework/qa/complex/path_substitution/PathSubstitutionTest.java @@ -0,0 +1,294 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package complex.path_substitution; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; + +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.XStringSubstitution; + +/** + * + */ +public class PathSubstitutionTest +{ + + // all substitution variables + private VariableContainer substVars = null; + + /** + * Create an array with all substitution variables + */ + @Before public void initialize() + { + substVars = new VariableContainer(); + substVars.add("$(prog)", true, true); + substVars.add("$(inst)", true, true); + substVars.add("$(user)", true, true); + substVars.add("$(work)", true, true); + substVars.add("$(home)", true, true); + substVars.add("$(temp)", true, true); + substVars.add("$(lang)", false, false); + substVars.add("$(username)", false, false); + substVars.add("$(langid)", false, false); + substVars.add("$(vlang)", false, false); + // path won't resubstitute + substVars.add("$(path)", true, false); + } + + /** + * One actual test: as the method 'getTestMethodNames()' tells. + */ + @Test public void checkXStringSubstitution() + { + XMultiServiceFactory xMSF = getMSF(); + System.out.println("---- Testing the XStringSubstitution interface ----"); + System.out.println("Create instance of test object.\n"); + XStringSubstitution oObj = null; + try + { + Object x = xMSF.createInstance( + "com.sun.star.util.PathSubstitution"); + oObj = UnoRuntime.queryInterface(XStringSubstitution.class, x); + if (oObj == null) + { + throw new com.sun.star.uno.Exception(); + } + } + catch (com.sun.star.uno.Exception e) + { + System.out.println(e.getClass().getName()); + System.out.println("Message: " + e.getMessage()); + fail("Could not create an instance of the test object."); + return; + } + + for (int i = 0; i < substVars.size(); i++) + { + String var = substVars.getVariable(i); + System.out.println("Testing var '" + var + "'"); + try + { + String substVal = oObj.getSubstituteVariableValue(var); + System.out.println("\tvalue '" + substVal + "'"); + substVars.putValue(i, substVal); + + // simple check: let path in a string replace + String substString = var + "/additional/path"; + + System.out.println("Substitute '" + substString + "'"); + String newValue = oObj.substituteVariables(substString, true); + System.out.println("Return value '" + newValue + "'"); + // 2do: better check for correct substitution + assertTrue("Did not substitute '" + + substString + "' to '" + newValue + + "' correctly:", newValue.startsWith(substVal)); + + // simple check part two: + //make substitution backwards if possible + if (substVars.canReSubstitute(i)) + { + substString = substVal + "/additional/path"; + + System.out.println("Substitute backwards '" + substString + "'"); + newValue = oObj.reSubstituteVariables(substString); + System.out.println("Return value '" + newValue + "'"); + // 2do: better check for correct substitution + assertTrue("Did not reSubstitute '" + + substString + "' to '" + newValue + + "' correctly:", checkResubstitute(newValue, var)); + } + + // simple check part three: look if replace + //in middle of text works + substString = "file:///starting/" + var + "/path"; + + String sCanSubstAllPos; + if (substVars.onlySubstituteAtBegin(i)) + sCanSubstAllPos = "NO"; + else + sCanSubstAllPos = "YES"; + System.out.println("Variable can substitute within string: "+sCanSubstAllPos); + System.out.println("Substitute '" + substString + "'"); + newValue = oObj.substituteVariables(substString, false); + System.out.println("Return value '" + newValue + "'"); + boolean erg = true; + if (substVars.onlySubstituteAtBegin(i)) + { + // in this case it should not have worked + erg = newValue.indexOf(substVal) == -1; + } + else + { + erg = newValue.indexOf(substVal) != -1; + } + assertTrue("Did not substitute '" + + substString + "' to '" + newValue + + "' correctly:", erg); + + } + catch (com.sun.star.uno.Exception e) + { + System.out.println(e.getClass().getName()); + System.out.println("Message: " + e.getMessage()); + fail("Could not create an instance of the test object."); + return; + } + System.out.println("Finish testing '" + var + "'\n"); + } + + // check of greedy resubstitution + String prog = "$(prog)"; + String inst = "$(inst)"; + String instPth = substVars.getValue(inst); + String progPth = substVars.getValue(prog); + + if (progPth.startsWith(instPth) && instPth.startsWith(progPth)) + { + System.out.println("Greedy ReSubstitute"); + String substString = progPth + "/additional/path"; + String newVal = oObj.reSubstituteVariables(substString); + System.out.println("String '" + substString + + "' should be resubstituted with"); + System.out.println("Variable '" + prog + "' instead of Variable '" + + inst + "'"); + assertTrue("Did not reSubstitute '" + substString + + "' to '" + newVal + "' correctly:", + newVal.startsWith(prog)); + } + + System.out.println( + "---- Finish testing the XStringSubstitution interface ----"); + } + + /** + * test the resubstitution + * @return true, if resubstitution is correct. + */ + private boolean checkResubstitute(String subst, String original) + { + // simple: subst starts with original + if (subst.startsWith(original)) + { + return true; + } + else + { // hard: been resubstituted with a different variable. + for (int i = 0; i < substVars.size(); i++) + { + String var = substVars.getVariable(i); + if (subst.startsWith(var) && original.startsWith(original)) + { + return true; + } + } + } + return false; + } + + /** + * Class for containing the substitution variables with their + * values and some information. + */ + private static class VariableContainer + { + + public ArrayList varName; + public ArrayList varValue; + public ArrayList substAtBegin; + public ArrayList resubst; + + public VariableContainer() + { + varName = new ArrayList(); + varValue = new ArrayList(); + substAtBegin = new ArrayList(); + resubst = new ArrayList(); + } + + public void add(String var, boolean onlySubstAtBegin, + boolean canResubst) + { + varName.add(var); + this.substAtBegin.add(Boolean.valueOf(onlySubstAtBegin)); + this.resubst.add(Boolean.valueOf(canResubst)); + } + + public void putValue(int i, String val) + { + varValue.add(i, val); + } + + public int size() + { + return varName.size(); + } + + public String getVariable(int i) + { + return varName.get(i); + } + + public String getValue(String var) + { + return varValue.get(varName.indexOf(var)); + } + + public boolean onlySubstituteAtBegin(int i) + { + return substAtBegin.get(i).booleanValue(); + } + + public boolean canReSubstitute(int i) + { + return resubst.get(i).booleanValue(); + } + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + System.out.println("setUpConnection()"); + connection.setUp(); + } + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println("tearDownConnection()"); + connection.tearDown(); + } + private static final OfficeConnection connection = new OfficeConnection(); +} diff --git a/framework/qa/cppunit/data/double-loading.odt b/framework/qa/cppunit/data/double-loading.odt new file mode 100644 index 000000000..ce990fc5c Binary files /dev/null and b/framework/qa/cppunit/data/double-loading.odt differ diff --git a/framework/qa/cppunit/data/empty.fodp b/framework/qa/cppunit/data/empty.fodp new file mode 100644 index 000000000..3c2a4cf2c --- /dev/null +++ b/framework/qa/cppunit/data/empty.fodp @@ -0,0 +1,2 @@ + + diff --git a/framework/qa/cppunit/dispatchtest.cxx b/framework/qa/cppunit/dispatchtest.cxx new file mode 100644 index 000000000..16a4ecb51 --- /dev/null +++ b/framework/qa/cppunit/dispatchtest.cxx @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +/// Sample interception implementation that asserts getInterceptedURLs() and queryDispatch() is in sync. +class MyInterceptor + : public cppu::WeakImplHelper +{ + uno::Reference m_xMaster; + uno::Reference m_xSlave; + uno::Sequence m_aDisabledCommands; + int m_nExpected; + int m_nUnexpected; + +public: + MyInterceptor(); + + /// Number of queryDispatch() calls that operate on a command advertised by getInterceptedURLs(). + int getExpected(); + /// Number of queryDispatch() calls that operate on a command not advertised by getInterceptedURLs(). + int getUnexpected(); + + // frame::XInterceptorInfo + virtual uno::Sequence SAL_CALL getInterceptedURLs() override; + + // frame::XDispatchProviderInterceptor + virtual void SAL_CALL setMasterDispatchProvider( + const uno::Reference& xNewSupplier) override; + virtual uno::Reference SAL_CALL getMasterDispatchProvider() override; + virtual void SAL_CALL + setSlaveDispatchProvider(const uno::Reference& xNewSupplier) override; + virtual uno::Reference SAL_CALL getSlaveDispatchProvider() override; + + // frame::XDispatchProvider + virtual uno::Sequence> SAL_CALL + queryDispatches(const uno::Sequence& rRequests) override; + virtual uno::Reference + SAL_CALL queryDispatch(const util::URL& rURL, const OUString& rTargetFrameName, + sal_Int32 SearchFlags) override; +}; + +MyInterceptor::MyInterceptor() + : m_aDisabledCommands{ ".uno:Bold" } + , m_nExpected(0) + , m_nUnexpected(0) +{ +} + +int MyInterceptor::getExpected() +{ + int nRet = m_nExpected; + m_nExpected = 0; + return nRet; +} + +int MyInterceptor::getUnexpected() +{ + int nRet = m_nUnexpected; + m_nUnexpected = 0; + return nRet; +} + +uno::Sequence MyInterceptor::getInterceptedURLs() { return m_aDisabledCommands; } + +void MyInterceptor::setMasterDispatchProvider( + const uno::Reference& xNewSupplier) +{ + m_xMaster = xNewSupplier; +} + +uno::Reference MyInterceptor::getMasterDispatchProvider() +{ + return m_xMaster; +} + +void MyInterceptor::setSlaveDispatchProvider( + const uno::Reference& xNewSupplier) +{ + m_xSlave = xNewSupplier; +} + +uno::Reference MyInterceptor::getSlaveDispatchProvider() +{ + return m_xSlave; +} + +uno::Sequence> +MyInterceptor::queryDispatches(const uno::Sequence& rRequests) +{ + uno::Sequence> aResult(rRequests.getLength()); + auto aResultRange = asNonConstRange(aResult); + + for (sal_Int32 i = 0; i < rRequests.getLength(); ++i) + { + aResultRange[i] = queryDispatch(rRequests[i].FeatureURL, rRequests[i].FrameName, + rRequests[i].SearchFlags); + } + + return aResult; +} + +uno::Reference MyInterceptor::queryDispatch(const util::URL& rURL, + const OUString& /*rTargetFrameName*/, + sal_Int32 /*SearchFlags*/) +{ + if (std::find(std::cbegin(m_aDisabledCommands), std::cend(m_aDisabledCommands), rURL.Complete) + != std::cend(m_aDisabledCommands)) + ++m_nExpected; + else + ++m_nUnexpected; + + return uno::Reference(); +} + +/// Tests how InterceptionHelper invokes a registered interceptor. +class DispatchTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +protected: + uno::Reference mxComponent; + +public: + virtual void setUp() override; + virtual void tearDown() override; +}; + +void DispatchTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void DispatchTest::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +CPPUNIT_TEST_FIXTURE(DispatchTest, testInterception) +{ + mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument"); + uno::Reference xModel(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xModel.is()); + + uno::Reference xRegistration( + xModel->getCurrentController()->getFrame(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xRegistration.is()); + + rtl::Reference pInterceptor(new MyInterceptor()); + xRegistration->registerDispatchProviderInterceptor(pInterceptor); + + dispatchCommand(mxComponent, ".uno:Bold", {}); + CPPUNIT_ASSERT_EQUAL(1, pInterceptor->getExpected()); + CPPUNIT_ASSERT_EQUAL(0, pInterceptor->getUnexpected()); + dispatchCommand(mxComponent, ".uno:Italic", {}); + CPPUNIT_ASSERT_EQUAL(1, pInterceptor->getExpected()); + // This was 1: MyInterceptor::queryDispatch() was called for .uno:Italic. + CPPUNIT_ASSERT_EQUAL(0, pInterceptor->getUnexpected()); +} + +constexpr OUStringLiteral DATA_DIRECTORY = u"/framework/qa/cppunit/data/"; + +CPPUNIT_TEST_FIXTURE(DispatchTest, testSfxOfficeDispatchDispose) +{ + // this test doesn't work with a new document because of aURL.Main check in SfxBaseController::dispatch() + mxComponent = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY) + "empty.fodp", + "com.sun.star.presentation.PresentationDocument"); + uno::Reference xModel(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xModel.is()); + uno::Reference xController(xModel->getCurrentController()); + CPPUNIT_ASSERT(xController.is()); + uno::Reference xFrame(xController->getFrame(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xFrame.is()); + + uno::Reference xParser(util::URLTransformer::create(mxComponentContext)); + util::URL url; + url.Complete = xModel->getURL() + "#dummy"; + xParser->parseStrict(url); + + uno::Reference xDisp(xFrame->queryDispatch(url, "", 0)); + CPPUNIT_ASSERT(xDisp.is()); + + mxComponent->dispose(); + + util::URL urlSlot; + urlSlot.Complete = "slot:5598"; + xParser->parseStrict(urlSlot); + // crashed with UAF + xDisp->dispatch(urlSlot, {}); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/qa/cppunit/loadenv.cxx b/framework/qa/cppunit/loadenv.cxx new file mode 100644 index 000000000..4842645bb --- /dev/null +++ b/framework/qa/cppunit/loadenv.cxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +/// Covers framework/source/loadenv/ fixes. +class Test : public test::BootstrapFixture, public unotest::MacrosTest +{ +public: + void setUp() override; +}; + +void Test::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +constexpr OUStringLiteral DATA_DIRECTORY = u"/framework/qa/cppunit/data/"; + +class DocumentOpener +{ +public: + DECL_STATIC_LINK(DocumentOpener, OpenDocument, void*, void); +}; + +IMPL_STATIC_LINK(DocumentOpener, OpenDocument, void*, pArg, void) +{ + CPPUNIT_ASSERT(pArg); + auto pURL = static_cast(pArg); + uno::Reference xComponentContext + = comphelper::getProcessComponentContext(); + uno::Reference xDesktop = frame::Desktop::create(xComponentContext); + xDesktop->loadComponentFromURL(*pURL, "_default", 0, {}); + delete pURL; +} + +CPPUNIT_TEST_FIXTURE(Test, testDoubleLoading) +{ + // Try to load the same document twice. This is similar to trying to execute the soffice process + // twice: in that case the 2nd instance forwards to the 1st instance and then uses the same code + // path. + for (int i = 0; i < 2; ++i) + { + auto pURL = std::make_unique(m_directories.getURLFromSrc(DATA_DIRECTORY) + + "double-loading.odt"); + Application::PostUserEvent(LINK(nullptr, DocumentOpener, OpenDocument), pURL.release()); + } + Scheduler::ProcessEventsToIdle(); + + // Verify that the 2nd load didn't happen, since it's the same document. + uno::Reference xFrames = mxDesktop->getFrames(); + // Without the accompanying fix in place, this failed with: + // - Expected: 1 + // - Actual : 2 + // i.e. the document was loaded twice, into two separate frames/windows. + CPPUNIT_ASSERT_EQUAL(static_cast(1), xFrames->getCount()); + + // Close the document, now that we know we have a single one. + uno::Reference xFrame(xFrames->getByIndex(0), uno::UNO_QUERY); + xFrame->getController()->getModel()->dispose(); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/qa/cppunit/services.cxx b/framework/qa/cppunit/services.cxx new file mode 100644 index 000000000..873ea5938 --- /dev/null +++ b/framework/qa/cppunit/services.cxx @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +/// Covers framework/source/services/ fixes. +class Test : public test::BootstrapFixture, public unotest::MacrosTest +{ +protected: + uno::Reference mxComponent; + +public: + void setUp() override; + void tearDown() override; + uno::Reference& getComponent() { return mxComponent; } +}; + +void Test::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void Test::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +/// Invokes XFrameImpl::loadComponentFromURL() on a thread. +class TestThread : public salhelper::Thread +{ + uno::Reference mxComponentLoader; + uno::Reference& mrComponent; + +public: + TestThread(const uno::Reference& xComponentLoader, + uno::Reference& rComponent); + void execute() override; +}; + +TestThread::TestThread(const uno::Reference& xComponentLoader, + uno::Reference& rComponent) + : salhelper::Thread("TestThread") + , mxComponentLoader(xComponentLoader) + , mrComponent(rComponent) +{ +} + +void TestThread::execute() +{ + sal_Int32 nSearchFlags = frame::FrameSearchFlag::AUTO; + uno::Sequence aArguments = { + comphelper::makePropertyValue("OnMainThread", true), + }; + // Note how this is invoking loadComponentFromURL() on a frame, not on the desktop, as usual. + mrComponent = mxComponentLoader->loadComponentFromURL("private:factory/swriter", "_self", + nSearchFlags, aArguments); +} + +CPPUNIT_TEST_FIXTURE(Test, testLoadComponentFromURL) +{ + // Without the accompanying fix in place, this test would have failed with: + // thread 1: comphelper::SolarMutex::doRelease end: m_nCount is 1 + // thread 2: vcl::SolarThreadExecutor::execute: before SolarMutexReleaser ctor + // thread 2: comphelper::SolarMutex::doRelease start: m_nCount is 1, bUnlockAll is 1 + // thread 2: comphelper::SolarMutex::doRelease: failed IsCurrentThread() check, will abort + // Notice how thread 2 attempts to release the solar mutex while thread 1 holds it. + + // Create a default window, so by the time the thread would post a user event, it doesn't need + // the solar mutex to process a SendMessageW() call on Windows. + ScopedVclPtrInstance xWindow(nullptr, WB_APP | WB_STDWORK); + // Variable is not used, it holds the default window. + (void)xWindow; + + rtl::Reference xThread; + { + // Start the thread that will load the component, but hold the solar mutex for now, so we + // can see if it blocks. + SolarMutexGuard guard; + uno::Reference xFrame = mxDesktop->findFrame("_blank", /*nSearchFlags=*/0); + uno::Reference xComponentLoader(xFrame, uno::UNO_QUERY); + xThread = new TestThread(xComponentLoader, getComponent()); + xThread->launch(); + // If loadComponentFromURL() doesn't lock the solar mutex, the test will abort here. + osl::Thread::wait(std::chrono::seconds(1)); + } + { + // Now release the solar mutex, so the thread can post the task on the main loop. + SolarMutexReleaser releaser; + osl::Thread::wait(std::chrono::seconds(1)); + } + { + // Spin the main loop. + SolarMutexGuard guard; + Scheduler::ProcessEventsToIdle(); + } + { + // Stop the thread. + SolarMutexReleaser releaser; + xThread->join(); + } +} + +CPPUNIT_TEST_FIXTURE(Test, testURLTransformer_parseSmart) +{ + // Without the accompanying fix in place, this test would have failed with + // "www.example.com:" treated as scheme, "/8080/foo/" as path, "bar?q=baz" + // as name, and "F" as fragment. + + css::util::URL aURL; + aURL.Complete = "www.example.com:8080/foo/bar?q=baz#F"; + css::uno::Reference xParser(css::util::URLTransformer::create(mxComponentContext)); + CPPUNIT_ASSERT(xParser->parseSmart(aURL, "http:")); + CPPUNIT_ASSERT_EQUAL(OUString("http://www.example.com:8080/foo/bar?q=baz#F"), aURL.Complete); + CPPUNIT_ASSERT_EQUAL(OUString("http://www.example.com:8080/foo/bar"), aURL.Main); + CPPUNIT_ASSERT_EQUAL(OUString("http://"), aURL.Protocol); + CPPUNIT_ASSERT(aURL.User.isEmpty()); + CPPUNIT_ASSERT(aURL.Password.isEmpty()); + CPPUNIT_ASSERT_EQUAL(OUString("www.example.com"), aURL.Server); + CPPUNIT_ASSERT_EQUAL(sal_Int16(8080), aURL.Port); + CPPUNIT_ASSERT_EQUAL(OUString("/foo/"), aURL.Path); + CPPUNIT_ASSERT_EQUAL(OUString("bar"), aURL.Name); + CPPUNIT_ASSERT_EQUAL(OUString("q=baz"), aURL.Arguments); + CPPUNIT_ASSERT_EQUAL(OUString("F"), aURL.Mark); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/qa/unoapi/framework.sce b/framework/qa/unoapi/framework.sce new file mode 100644 index 000000000..ed1497d6d --- /dev/null +++ b/framework/qa/unoapi/framework.sce @@ -0,0 +1,51 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# 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 . +# +-o fwl.ContentHandlerFactory +-o fwl.FilterFactory +-o fwl.FrameLoaderFactory +-o fwl.SubstituteVariables +#i113245 -o fwl.TypeDetection +#i84346 -o fwl.PathSettings +-o fwk.DispatchRecorder +-o fwk.DispatchRecorderSupplier +-o fwk.FooterMenuController +-o fwk.StatusBarControllerFactory +-o fwk.ToolBarsMenuController +-o fwk.UICategoryDescription +#i84423 -o fwk.JobExecutor +#i84423 -o fwk.JobHandler +-o fwk.MailToDispatcher +-o fwk.ServiceHandler +-o fwk.URLTransformer +-o fwk.MacrosMenuController +#i112746 -o fwk.ModuleManager +-o fwk.UIElementFactoryManager +-o fwk.UICommandDescription +-o fwk.LayoutManager +-o fwk.UIConfigurationManager +-o fwk.MenuBarFactory +-o fwk.FontSizeMenuController +-o fwk.HeaderMenuController +-o fwk.ControlMenuController +-o fwk.FontMenuController +-o fwk.ModuleUIConfigurationManagerSupplier +-o fwk.ModuleUIConfigurationManager +#i84321 -o fwk.PopupMenuControllerFactory +#i88644 -o fwk.Frame +-o fwk.Desktop + diff --git a/framework/qa/unoapi/knownissues.xcl b/framework/qa/unoapi/knownissues.xcl new file mode 100644 index 000000000..d1255e611 --- /dev/null +++ b/framework/qa/unoapi/knownissues.xcl @@ -0,0 +1,77 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# 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 . +# + +### 112552 ### +fwk.JobHandler::com::sun::star::frame::XDispatchProvider +fwk.JobHandler::com::sun::star::lang::XInitialization + +### i8242 ### +fwk.Desktop::com::sun::star::lang::XComponent + +### i30570 ### +fwl.TypeDetection::com::sun::star::container::XNameReplace + +### i50165 ### +fwk.UIConfigurationManager::com::sun::star::ui::XUIConfigurationStorage +fwk.UIConfigurationManager::com::sun::star::ui::XUIConfigurationPersistence +fwk.UIConfigurationManager::com::sun::star::ui::XUIConfiguration +fwk.UIConfigurationManager::com::sun::star::ui::XUIConfigurationManager + +### i50578 ### +fwk.StatusBarControllerFactory::com::sun::star::lang::XMultiComponentFactory + +### i68698 ### +fwl.PathSettings::com::sun::star::beans::XMultiPropertySet + +### i74020 ### +fwl.FilterFactory::com::sun::star::lang::XMultiServiceFactory + +### i30570 ### +fwl.FilterFactory::com::sun::star::container::XNameReplace + +### i84321 ### +fwk.PopupMenuControllerFactory +# -> disabled in framework.sce + +### i84346 ### +fwl.PathSettings::com::sun::star::beans::XMultiPropertySet +#-> disabled in framework.sce + +### i84423 ### +fwk.JobExecutor +fwk.JobHandler +#-> disabled in framework.sce + +### i88635 ### +fwk.Desktop::com::sun::star::frame::XFramesSupplier + +### i87526 ### +fwk.Frame::com::sun::star::lang::XComponent + +### i87865 ### +fwk.Desktop::com::sun::star::frame::XDesktop + +### i88644 ### +fwk.Frame +#-> disabled in framework.sce + +### i90345 ### +fwk.URLTransformer::com::sun::star::util::XURLTransformer + +### i111180 ### +fwk.Desktop::com::sun::star::frame::XComponentLoader diff --git a/framework/qa/unoapi/testdocuments/Calc_Link.sxc b/framework/qa/unoapi/testdocuments/Calc_Link.sxc new file mode 100644 index 000000000..086c04fe0 Binary files /dev/null and b/framework/qa/unoapi/testdocuments/Calc_Link.sxc differ diff --git a/framework/qa/unoapi/testdocuments/Writer_link.sxw b/framework/qa/unoapi/testdocuments/Writer_link.sxw new file mode 100644 index 000000000..5e5c8bdcb Binary files /dev/null and b/framework/qa/unoapi/testdocuments/Writer_link.sxw differ diff --git a/framework/qa/unoapi/testdocuments/XTypeDetection.sxw b/framework/qa/unoapi/testdocuments/XTypeDetection.sxw new file mode 100644 index 000000000..b241f4ed8 Binary files /dev/null and b/framework/qa/unoapi/testdocuments/XTypeDetection.sxw differ diff --git a/framework/qa/unoapi/testdocuments/delete.cfg b/framework/qa/unoapi/testdocuments/delete.cfg new file mode 100644 index 000000000..31fef95a0 Binary files /dev/null and b/framework/qa/unoapi/testdocuments/delete.cfg differ -- cgit v1.2.3