summaryrefslogtreecommitdiffstats
path: root/sfx2/qa/cppunit
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sfx2/qa/cppunit
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sfx2/qa/cppunit')
-rw-r--r--sfx2/qa/cppunit/data/reload-page.odgbin0 -> 8824 bytes
-rw-r--r--sfx2/qa/cppunit/doc.cxx151
-rw-r--r--sfx2/qa/cppunit/misc/hello.odtbin0 -> 8159 bytes
-rw-r--r--sfx2/qa/cppunit/test_classification.cxx112
-rw-r--r--sfx2/qa/cppunit/test_controlleritem.cxx58
-rw-r--r--sfx2/qa/cppunit/test_metadatable.cxx248
-rw-r--r--sfx2/qa/cppunit/test_misc.cxx201
-rw-r--r--sfx2/qa/cppunit/view.cxx64
8 files changed, 834 insertions, 0 deletions
diff --git a/sfx2/qa/cppunit/data/reload-page.odg b/sfx2/qa/cppunit/data/reload-page.odg
new file mode 100644
index 0000000000..0e9cf08649
--- /dev/null
+++ b/sfx2/qa/cppunit/data/reload-page.odg
Binary files differ
diff --git a/sfx2/qa/cppunit/doc.cxx b/sfx2/qa/cppunit/doc.cxx
new file mode 100644
index 0000000000..9eea6d2939
--- /dev/null
+++ b/sfx2/qa/cppunit/doc.cxx
@@ -0,0 +1,151 @@
+/* -*- 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 <test/unoapi_test.hxx>
+
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/sfxbasemodel.hxx>
+#include <osl/file.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+
+using namespace com::sun::star;
+
+namespace
+{
+/// Covers sfx2/source/doc/ fixes.
+class Test : public UnoApiTest
+{
+public:
+ Test()
+ : UnoApiTest("/sfx2/qa/cppunit/data/")
+ {
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testNoGrabBagShape)
+{
+ // Load a document and select the first shape.
+ css::uno::Sequence<css::beans::PropertyValue> aArgs{ comphelper::makePropertyValue("ReadOnly",
+ true) };
+ mxComponent = loadFromDesktop("private:factory/simpress", "", aArgs);
+ uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(xModel, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xDrawPage(
+ xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
+ uno::Any aShape = xDrawPage->getByIndex(0);
+ uno::Reference<view::XSelectionSupplier> xController(xModel->getCurrentController(),
+ uno::UNO_QUERY);
+ xController->select(aShape);
+
+ // See if it has a signing certificate associated.
+ auto pBaseModel = dynamic_cast<SfxBaseModel*>(xModel.get());
+ CPPUNIT_ASSERT(pBaseModel);
+ SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
+ // which was not caught later, resulting in a crash.
+ pObjectShell->GetSignPDFCertificate();
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTempFilePath)
+{
+ // Create a test file in a directory that contains the URL-encoded "testÿ" string.
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ auto pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+ CPPUNIT_ASSERT(pBaseModel);
+ OUString aTargetDir
+ = m_directories.getURLFromWorkdir(u"CppunitTest/sfx2_doc.test.user/test%25C3%25Bf");
+ osl::Directory::create(aTargetDir);
+ OUString aTargetFile = aTargetDir + "/test.odt";
+ css::uno::Sequence<css::beans::PropertyValue> aArgs{ comphelper::makePropertyValue(
+ "FilterName", OUString("writer8")) };
+ pBaseModel->storeAsURL(aTargetFile, aArgs);
+ mxComponent->dispose();
+
+ // Load it and export to PDF.
+ mxComponent = loadFromDesktop(aTargetFile);
+ pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+ OUString aPdfTarget = aTargetDir + "/test.pdf";
+ css::uno::Sequence<css::beans::PropertyValue> aPdfArgs{ comphelper::makePropertyValue(
+ "FilterName", OUString("writer_pdf_Export")) };
+ // Without the accompanying fix in place, this test would have failed on Windows with:
+ // An uncaught exception of type com.sun.star.io.IOException
+ // because we first tried to create a temp file next to test.odt in a directory named
+ // "test%25C3%25Bf" instead of a directory named "test%C3%Bf".
+ pBaseModel->storeToURL(aPdfTarget, aPdfArgs);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSetDocumentPropertiesUpdate)
+{
+ // Given a document with 3 custom props, 2 Zotero ones and one other:
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ auto pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+ CPPUNIT_ASSERT(pBaseModel);
+ uno::Reference<document::XDocumentProperties> xDP = pBaseModel->getDocumentProperties();
+ uno::Reference<beans::XPropertyContainer> xUDP = xDP->getUserDefinedProperties();
+ xUDP->addProperty("ZOTERO_PREF_1", beans::PropertyAttribute::REMOVABLE,
+ uno::Any(OUString("foo")));
+ xUDP->addProperty("ZOTERO_PREF_2", beans::PropertyAttribute::REMOVABLE,
+ uno::Any(OUString("bar")));
+ xUDP->addProperty("OTHER", beans::PropertyAttribute::REMOVABLE, uno::Any(OUString("baz")));
+
+ // When updating the Zotero ones (1 update, 1 removal):
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "UpdatedProperties": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "NamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_PREF_"
+ },
+ "UserDefinedProperties": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "ZOTERO_PREF_1": {
+ "type": "string",
+ "value": "test"
+ }
+ }
+ }
+ }
+ }
+}
+)json"_ostr);
+ uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:SetDocumentProperties", aArgs);
+
+ // Then make sure that OTHER is still there and that ZOTERO_PREF_1 + ZOTERO_PREF_2 gets updated
+ // to the new value of a single ZOTERO_PREF_1:
+ uno::Reference<beans::XPropertyAccess> xUDPAccess(xUDP, uno::UNO_QUERY);
+ comphelper::SequenceAsHashMap aMap(xUDPAccess->getPropertyValues());
+ auto it = aMap.find("ZOTERO_PREF_1");
+ CPPUNIT_ASSERT(it != aMap.end());
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: test
+ // - Actual : foo
+ // i.e. ZOTERO_PREF_1 was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("test"), it->second.get<OUString>());
+ CPPUNIT_ASSERT(bool(aMap.find("ZOTERO_PREF_2") == aMap.end()));
+ CPPUNIT_ASSERT(aMap.find("OTHER") != aMap.end());
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/qa/cppunit/misc/hello.odt b/sfx2/qa/cppunit/misc/hello.odt
new file mode 100644
index 0000000000..23ce6a4db9
--- /dev/null
+++ b/sfx2/qa/cppunit/misc/hello.odt
Binary files differ
diff --git a/sfx2/qa/cppunit/test_classification.cxx b/sfx2/qa/cppunit/test_classification.cxx
new file mode 100644
index 0000000000..ffa90089fd
--- /dev/null
+++ b/sfx2/qa/cppunit/test_classification.cxx
@@ -0,0 +1,112 @@
+/* -*- 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 <test/unoapi_test.hxx>
+
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/DispatchHelper.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+
+/// Tests the handling of the .uno:ClassificationApply command in various applications.
+class ClassificationTest : public UnoApiTest
+{
+ void testClassification();
+
+public:
+ ClassificationTest()
+ : UnoApiTest("/sfx2/qa/cppunit/data/")
+ {
+ }
+
+ void testWriter();
+ void testCalc();
+ void testImpress();
+
+ CPPUNIT_TEST_SUITE(ClassificationTest);
+ CPPUNIT_TEST(testWriter);
+ CPPUNIT_TEST(testCalc);
+ CPPUNIT_TEST(testImpress);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void ClassificationTest::testClassification()
+{
+ uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
+ {
+ {"Name", uno::Any(OUString("Non-Business"))},
+ {"Type", uno::Any(OUString("urn:bails:ExportControl:"))},
+ }));
+ dispatchCommand(mxComponent, ".uno:ClassificationApply", aPropertyValues);
+
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xDocumentPropertiesSupplier.is());
+ uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+ uno::Reference<beans::XPropertySet> xPropertySet(xDocumentProperties->getUserDefinedProperties(), uno::UNO_QUERY);
+ uno::Any aAny = xPropertySet->getPropertyValue("urn:bails:ExportControl:BusinessAuthorizationCategory:Identifier");
+ CPPUNIT_ASSERT_EQUAL(OUString("urn:example:tscp:1:non-business"), aAny.get<OUString>());
+
+ aPropertyValues = comphelper::InitPropertySequence(
+ {
+ {"Name", uno::Any(OUString("Confidential"))},
+ {"Type", uno::Any(OUString("urn:bails:NationalSecurity:"))},
+ });
+ dispatchCommand(mxComponent, ".uno:ClassificationApply", aPropertyValues);
+ aAny = xPropertySet->getPropertyValue("urn:bails:NationalSecurity:BusinessAuthorizationCategory:Identifier");
+ CPPUNIT_ASSERT_EQUAL(OUString("urn:example:tscp:1:confidential"), aAny.get<OUString>());
+
+ aPropertyValues = comphelper::InitPropertySequence(
+ {
+ {"Name", uno::Any(OUString("Internal Only"))},
+ {"Type", uno::Any(OUString("urn:bails:IntellectualProperty:"))},
+ });
+ dispatchCommand(mxComponent, ".uno:ClassificationApply", aPropertyValues);
+ aAny = xPropertySet->getPropertyValue("urn:bails:IntellectualProperty:BusinessAuthorizationCategory:Identifier");
+ CPPUNIT_ASSERT_EQUAL(OUString("urn:example:tscp:1:internal-only"), aAny.get<OUString>());
+}
+
+void ClassificationTest::testWriter()
+{
+ // Test SID_CLASSIFICATION_APPLY handling in SwDocShell::Execute().
+ mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
+ // This resulted in a beans::UnknownPropertyException when the request wasn't handled.
+ testClassification();
+}
+
+void ClassificationTest::testCalc()
+{
+ // Test SID_CLASSIFICATION_APPLY handling in ScFormatShell::ExecuteStyle().
+ mxComponent = loadFromDesktop("private:factory/scalc", "com.sun.star.sheet.SpreadsheetDocument");
+ // This resulted in a beans::UnknownPropertyException when the request wasn't handled.
+ testClassification();
+}
+
+void ClassificationTest::testImpress()
+{
+ // Test SID_CLASSIFICATION_APPLY handling in sd::DrawViewShell::FuTemporary().
+ mxComponent = loadFromDesktop("private:factory/simpress", "com.sun.star.presentation.PresentationDocument");
+ // This resulted in a beans::UnknownPropertyException when the request wasn't handled.
+ testClassification();
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ClassificationTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/qa/cppunit/test_controlleritem.cxx b/sfx2/qa/cppunit/test_controlleritem.cxx
new file mode 100644
index 0000000000..75d2205367
--- /dev/null
+++ b/sfx2/qa/cppunit/test_controlleritem.cxx
@@ -0,0 +1,58 @@
+/* -*- 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 <sal/types.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <sfx2/ctrlitem.hxx>
+
+namespace {
+
+class ControllerItemTest
+ : public ::CppUnit::TestFixture
+{
+public:
+ void test();
+
+ CPPUNIT_TEST_SUITE(ControllerItemTest);
+ CPPUNIT_TEST(test);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+};
+
+bool bDeleted = false;
+
+class FooController : public SfxControllerItem {
+public:
+ FooController() : SfxControllerItem() {}
+ virtual ~FooController() override { bDeleted = true; }
+};
+
+void ControllerItemTest::test()
+{
+ FooController *pController(new FooController());
+
+ // TESTME: binding, un-binding, re-binding, IsBound, SetId etc.
+
+ pController->dispose();
+ delete pController;
+ CPPUNIT_ASSERT( bDeleted );
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ControllerItemTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/qa/cppunit/test_metadatable.cxx b/sfx2/qa/cppunit/test_metadatable.cxx
new file mode 100644
index 0000000000..459f635d00
--- /dev/null
+++ b/sfx2/qa/cppunit/test_metadatable.cxx
@@ -0,0 +1,248 @@
+/* -*- 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 .
+ */
+
+#include <sal/types.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+#include <sfx2/Metadatable.hxx>
+#include <sfx2/XmlIdRegistry.hxx>
+
+#include <memory>
+
+
+using namespace ::com::sun::star;
+
+
+namespace {
+
+class MetadatableTest
+ : public ::CppUnit::TestFixture
+{
+public:
+ void test();
+
+ CPPUNIT_TEST_SUITE(MetadatableTest);
+ CPPUNIT_TEST(test);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+};
+
+class MockMetadatable
+ : public ::sfx2::Metadatable
+{
+private:
+ ::sfx2::IXmlIdRegistry & m_rRegistry;
+
+public:
+ MockMetadatable(::sfx2::IXmlIdRegistry & i_rReg,
+ bool const i_isInClip = false)
+ : m_rRegistry(i_rReg)
+ , m_bInClipboard(i_isInClip), m_bInUndo(false), m_bInContent(true) {}
+ bool m_bInClipboard;
+ bool m_bInUndo;
+ bool m_bInContent;
+ virtual bool IsInClipboard() const override { return m_bInClipboard; }
+ virtual bool IsInUndo() const override { return m_bInUndo; }
+ virtual bool IsInContent() const override { return m_bInContent; }
+ virtual ::sfx2::IXmlIdRegistry& GetRegistry() override { return m_rRegistry; }
+ virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override { return nullptr; }
+};
+
+void MetadatableTest::test()
+{
+ std::unique_ptr< ::sfx2::IXmlIdRegistry > const pReg(
+ ::sfx2::createXmlIdRegistry(false) );
+ std::unique_ptr< ::sfx2::IXmlIdRegistry > const pRegClip(
+ ::sfx2::createXmlIdRegistry(true) );
+
+ MockMetadatable m1(*pReg);
+ MockMetadatable m2(*pReg);
+ MockMetadatable m3(*pReg);
+ MockMetadatable m4(*pReg);
+ MockMetadatable m5(*pReg);
+ OUString empty;
+ OUString content( "content.xml" );
+ OUString sid3( "id3" );
+ OUString sid4( "id4" );
+ beans::StringPair id1(content, "id1");
+ beans::StringPair id2(content, "id2");
+ beans::StringPair id3(content, sid3);
+ beans::StringPair id4("styles.xml", sid4);
+ beans::StringPair id3e(empty, sid3);
+ beans::StringPair id4e(empty, sid4);
+ m1.SetMetadataReference(id1);
+ CPPUNIT_ASSERT_MESSAGE("set failed", bool(m1.GetMetadataReference() == id1));
+ try {
+ m2.SetMetadataReference(id1);
+ CPPUNIT_ASSERT_MESSAGE("set duplicate succeeded", false);
+ } catch (const lang::IllegalArgumentException &) { }
+ m1.SetMetadataReference(id1);
+ CPPUNIT_ASSERT_MESSAGE("set failed (existing)",
+ bool(m1.GetMetadataReference() == id1));
+ m1.EnsureMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("ensure failed (existing)",
+ bool(m1.GetMetadataReference() == id1));
+
+ m2.EnsureMetadataReference();
+ beans::StringPair m2id(m2.GetMetadataReference());
+ CPPUNIT_ASSERT_MESSAGE("ensure failed", !m2id.Second.isEmpty());
+ m2.EnsureMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("ensure failed (idempotent)",
+ bool(m2.GetMetadataReference() == m2id));
+
+ m1.m_bInUndo = true;
+ CPPUNIT_ASSERT_MESSAGE("move to undo failed",
+ m1.GetMetadataReference().Second.isEmpty());
+
+ m1.m_bInUndo = false;
+ CPPUNIT_ASSERT_MESSAGE("move from undo failed",
+ bool(m1.GetMetadataReference() == id1));
+
+ m1.m_bInUndo = true;
+ try {
+ m2.SetMetadataReference(id1); // steal!
+ } catch (lang::IllegalArgumentException &) {
+ CPPUNIT_FAIL("set duplicate to undo failed");
+ }
+ m1.m_bInUndo = false;
+ CPPUNIT_ASSERT_MESSAGE("move from undo: duplicate",
+ m1.GetMetadataReference().Second.isEmpty());
+
+ m3.RegisterAsCopyOf(m2);
+ CPPUNIT_ASSERT_MESSAGE("copy: source", bool(m2.GetMetadataReference() == id1));
+ CPPUNIT_ASSERT_MESSAGE("copy: duplicate",
+ m3.GetMetadataReference().Second.isEmpty());
+ m4.RegisterAsCopyOf(m3);
+ CPPUNIT_ASSERT_MESSAGE("copy: source", bool(m2.GetMetadataReference() == id1));
+ CPPUNIT_ASSERT_MESSAGE("copy: duplicate",
+ m3.GetMetadataReference().Second.isEmpty());
+ CPPUNIT_ASSERT_MESSAGE("copy: duplicate",
+ m4.GetMetadataReference().Second.isEmpty());
+ m2.m_bInUndo = true;
+ CPPUNIT_ASSERT_MESSAGE("duplicate to undo",
+ bool(m3.GetMetadataReference() == id1));
+ CPPUNIT_ASSERT_MESSAGE("duplicate to undo",
+ m2.GetMetadataReference().Second.isEmpty());
+ m2.m_bInUndo = false;
+ CPPUNIT_ASSERT_MESSAGE("duplicate from undo",
+ bool(m2.GetMetadataReference() == id1));
+ CPPUNIT_ASSERT_MESSAGE("duplicate from undo",
+ m3.GetMetadataReference().Second.isEmpty());
+
+ m4.EnsureMetadataReference(); // new!
+ beans::StringPair m4id(m4.GetMetadataReference());
+ CPPUNIT_ASSERT_MESSAGE("ensure on duplicate",
+ !m4id.Second.isEmpty());
+ CPPUNIT_ASSERT_MESSAGE("ensure on duplicate",
+ !(m4id == id1));
+
+ MockMetadatable mc1(*pRegClip, true); // in clipboard
+ MockMetadatable mc2(*pRegClip, true);
+ MockMetadatable mc3(*pRegClip, true);
+ MockMetadatable mc4(*pRegClip, true);
+ MockMetadatable m2p(*pReg);
+ MockMetadatable m3p(*pReg);
+
+ mc1.SetMetadataReference(id2);
+ CPPUNIT_ASSERT_MESSAGE("set failed", bool(mc1.GetMetadataReference() == id2));
+ try {
+ mc2.SetMetadataReference(id2);
+ CPPUNIT_FAIL("set duplicate succeeded");
+ } catch (const lang::IllegalArgumentException &) { }
+ mc1.SetMetadataReference(id2);
+ CPPUNIT_ASSERT_MESSAGE("set failed (existing)",
+ bool(mc1.GetMetadataReference() == id2));
+ mc1.EnsureMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("ensure failed (existing)",
+ bool(mc1.GetMetadataReference() == id2));
+ mc2.EnsureMetadataReference();
+ beans::StringPair mc2id(mc2.GetMetadataReference());
+ CPPUNIT_ASSERT_MESSAGE("ensure failed", !mc2id.Second.isEmpty());
+ mc2.EnsureMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("ensure failed (idempotent)",
+ bool(mc2.GetMetadataReference() == mc2id));
+ mc2.RemoveMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("remove failed",
+ mc2.GetMetadataReference().Second.isEmpty());
+
+ // set up mc2 as copy of m2 and mc3 as copy of m3
+ mc3.RegisterAsCopyOf(m3);
+ CPPUNIT_ASSERT_MESSAGE("copy to clipboard (latent)",
+ mc3.GetMetadataReference().Second.isEmpty() );
+ mc2.RegisterAsCopyOf(m2);
+ CPPUNIT_ASSERT_MESSAGE("copy to clipboard (non-latent)",
+ bool(mc2.GetMetadataReference() == id1));
+ // paste mc2 to m2p and mc3 to m3p
+ m2p.RegisterAsCopyOf(mc2);
+ CPPUNIT_ASSERT_MESSAGE("paste from clipboard (non-latent)",
+ m2p.GetMetadataReference().Second.isEmpty() );
+ m3p.RegisterAsCopyOf(mc3);
+ CPPUNIT_ASSERT_MESSAGE("paste from clipboard (latent)",
+ m3p.GetMetadataReference().Second.isEmpty() );
+ // delete m2, m2p, m3
+ m2.RemoveMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("remove failed",
+ m2.GetMetadataReference().Second.isEmpty());
+ CPPUNIT_ASSERT_MESSAGE("paste-remove (non-latent)",
+ bool(m2p.GetMetadataReference() == id1));
+ m2p.RemoveMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("remove failed",
+ m2p.GetMetadataReference().Second.isEmpty());
+ CPPUNIT_ASSERT_MESSAGE("paste-remove2 (non-latent)",
+ bool(m3.GetMetadataReference() == id1));
+ m3.RemoveMetadataReference();
+ CPPUNIT_ASSERT_MESSAGE("remove failed",
+ m3.GetMetadataReference().Second.isEmpty());
+ CPPUNIT_ASSERT_MESSAGE("paste-remove (latent)",
+ bool(m3p.GetMetadataReference() == id1));
+ // delete mc2
+ mc2.SetMetadataReference(beans::StringPair());
+ CPPUNIT_ASSERT_MESSAGE("in clipboard becomes non-latent",
+ mc3.GetMetadataReference().Second.isEmpty() );
+ // paste mc2
+ m2p.RegisterAsCopyOf(mc2);
+ CPPUNIT_ASSERT_MESSAGE("remove-paste",
+ m2p.GetMetadataReference().Second.isEmpty());
+ CPPUNIT_ASSERT_MESSAGE("remove-paste (stolen)",
+ bool(m3p.GetMetadataReference() == id1));
+
+ // auto-detect stream
+ m5.SetMetadataReference(id3e);
+ CPPUNIT_ASSERT_MESSAGE("auto-detect (content)",
+ bool(m5.GetMetadataReference() == id3));
+ m5.m_bInContent = false;
+ m5.SetMetadataReference(id4e);
+ CPPUNIT_ASSERT_MESSAGE("auto-detect (styles)",
+ bool(m5.GetMetadataReference() == id4));
+}
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MetadatableTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/qa/cppunit/test_misc.cxx b/sfx2/qa/cppunit/test_misc.cxx
new file mode 100644
index 0000000000..d80a037f6f
--- /dev/null
+++ b/sfx2/qa/cppunit/test_misc.cxx
@@ -0,0 +1,201 @@
+/* -*- 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 <sal/types.h>
+
+#ifndef _WIN32
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+#include <memory>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/document/DocumentProperties.hpp>
+#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+
+#include <test/unoapixml_test.hxx>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/app.hxx>
+#include <osl/file.hxx>
+
+
+using namespace ::com::sun::star;
+
+
+namespace {
+
+class MiscTest
+ : public UnoApiXmlTest
+{
+public:
+ MiscTest()
+ : UnoApiXmlTest("/sfx2/qa/cppunit/misc/")
+ {
+ }
+
+ virtual void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override
+ {
+ // ODF
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("office"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("meta"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:meta:1.0"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dc"), BAD_CAST("http://purl.org/dc/elements/1.1/"));
+ // used in testCustomMetadata
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("foo"), BAD_CAST("http://foo.net"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("baz"), BAD_CAST("http://baz.net"));
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(MiscTest, testODFCustomMetadata)
+{
+ uno::Reference<document::XDocumentProperties> const xProps(
+ ::com::sun::star::document::DocumentProperties::create(m_xContext));
+
+ OUString const url(m_directories.getURLFromSrc(u"/sfx2/qa/complex/sfx2/testdocuments/CUSTOM.odt"));
+ xProps->loadFromMedium(url, uno::Sequence<beans::PropertyValue>());
+ CPPUNIT_ASSERT_EQUAL(OUString(""), xProps->getAuthor());
+ uno::Sequence<beans::PropertyValue> mimeArgs({
+ beans::PropertyValue("MediaType", -1, uno::Any(OUString("application/vnd.oasis.opendocument.text")), beans::PropertyState_DIRECT_VALUE)
+ });
+ xProps->storeToMedium(maTempFile.GetURL(), mimeArgs);
+
+ // check that custom metadata is preserved
+ xmlDocUniquePtr pXmlDoc = parseExport("meta.xml");
+ assertXPathContent(pXmlDoc, "/office:document-meta/office:meta/bork"_ostr, "bork");
+ assertXPath(pXmlDoc, "/office:document-meta/office:meta/foo:bar"_ostr, 1);
+ assertXPath(pXmlDoc, "/office:document-meta/office:meta/foo:bar/baz:foo"_ostr, 1);
+ assertXPath(pXmlDoc, "/office:document-meta/office:meta/foo:bar/baz:foo[@baz:bar='foo']"_ostr);
+ assertXPathContent(pXmlDoc, "/office:document-meta/office:meta/foo:bar/foo:baz"_ostr, "bar");
+}
+
+CPPUNIT_TEST_FIXTURE(MiscTest, testNoThumbnail)
+{
+ // Load a document.
+ loadFromFile(u"hello.odt");
+
+ // Save it with the NoThumbnail option and assert that it has no thumbnail.
+#ifndef _WIN32
+ mode_t nMask = umask(022);
+#endif
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xStorable.is());
+ uno::Sequence<beans::PropertyValue> aProperties(
+ comphelper::InitPropertySequence({ { "NoThumbnail", uno::Any(true) } }));
+ osl::File::remove(maTempFile.GetURL());
+ xStorable->storeToURL(maTempFile.GetURL(), aProperties);
+ uno::Reference<packages::zip::XZipFileAccess2> xZipFile
+ = packages::zip::ZipFileAccess::createWithURL(m_xContext, maTempFile.GetURL());
+ CPPUNIT_ASSERT(!xZipFile->hasByName("Thumbnails/thumbnail.png"));
+
+#ifndef _WIN32
+ // Check permissions of the URL after store.
+ osl::DirectoryItem aItem;
+ CPPUNIT_ASSERT_EQUAL(osl::DirectoryItem::E_None,
+ osl::DirectoryItem::get(maTempFile.GetURL(), aItem));
+
+ osl::FileStatus aStatus(osl_FileStatus_Mask_Attributes);
+ CPPUNIT_ASSERT_EQUAL(osl::DirectoryItem::E_None, aItem.getFileStatus(aStatus));
+
+ // The following checks used to fail in the past, osl_File_Attribute_GrpRead was not set even if
+ // umask requested so:
+ CPPUNIT_ASSERT(aStatus.getAttributes() & osl_File_Attribute_GrpRead);
+ CPPUNIT_ASSERT(aStatus.getAttributes() & osl_File_Attribute_OthRead);
+
+ // Now "save as" again to trigger the "overwrite" case.
+ xStorable->storeToURL(maTempFile.GetURL(), {});
+ CPPUNIT_ASSERT_EQUAL(osl::DirectoryItem::E_None, aItem.getFileStatus(aStatus));
+ // The following check used to fail in the past, result had temp file
+ // permissions.
+ CPPUNIT_ASSERT(aStatus.getAttributes() & osl_File_Attribute_GrpRead);
+
+ umask(nMask);
+#endif
+}
+
+CPPUNIT_TEST_FIXTURE(MiscTest, testHardLinks)
+{
+#ifndef _WIN32
+ OUString aTargetDir = m_directories.getURLFromWorkdir(u"/CppunitTest/sfx2_misc.test.user/");
+ const OUString aURL(aTargetDir + "hello.odt");
+ osl::File::copy(createFileURL(u"hello.odt"), aURL);
+ OUString aTargetPath;
+ osl::FileBase::getSystemPathFromFileURL(aURL, aTargetPath);
+ OString aOld = aTargetPath.toUtf8();
+ aTargetPath += ".2";
+ OString aNew = aTargetPath.toUtf8();
+ int nRet = link(aOld.getStr(), aNew.getStr());
+ CPPUNIT_ASSERT_EQUAL(0, nRet);
+
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument");
+
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ xStorable->store();
+
+ struct stat buf;
+ // coverity[fs_check_call] - this is legitimate in the context of this test
+ nRet = stat(aOld.getStr(), &buf);
+ CPPUNIT_ASSERT_EQUAL(0, nRet);
+ // This failed: hard link count was 1, the hard link broke on store.
+ CPPUNIT_ASSERT(buf.st_nlink > 1);
+
+ // Test that symlinks are preserved as well.
+ nRet = remove(aNew.getStr());
+ CPPUNIT_ASSERT_EQUAL(0, nRet);
+ nRet = symlink(aOld.getStr(), aNew.getStr());
+ CPPUNIT_ASSERT_EQUAL(0, nRet);
+ xStorable->storeToURL(aURL + ".2", {});
+ nRet = lstat(aNew.getStr(), &buf);
+ CPPUNIT_ASSERT_EQUAL(0, nRet);
+ // This failed, the hello.odt.2 symlink was replaced with a real file.
+ CPPUNIT_ASSERT(bool(S_ISLNK(buf.st_mode)));
+#endif
+}
+
+CPPUNIT_TEST_FIXTURE(MiscTest, testOverwrite)
+{
+ // tdf#60237 - try to overwrite an existing file using the different settings of the Overwrite option
+ mxComponent
+ = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument");
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xStorable.is());
+
+ // overwrite the file using the default case of the Overwrite option (true)
+ CPPUNIT_ASSERT_NO_THROW(xStorable->storeToURL(maTempFile.GetURL(), {}));
+
+ // explicitly overwrite the file using the Overwrite option
+ CPPUNIT_ASSERT_NO_THROW(xStorable->storeToURL(
+ maTempFile.GetURL(),
+ comphelper::InitPropertySequence({ { "Overwrite", uno::Any(true) } })));
+
+ try
+ {
+ // overwrite an existing file with the Overwrite flag set to false
+ xStorable->storeToURL(maTempFile.GetURL(), comphelper::InitPropertySequence(
+ { { "Overwrite", uno::Any(false) } }));
+ CPPUNIT_ASSERT_MESSAGE("We expect an exception on overwriting an existing file", false);
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+}
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/qa/cppunit/view.cxx b/sfx2/qa/cppunit/view.cxx
new file mode 100644
index 0000000000..725cb5d02c
--- /dev/null
+++ b/sfx2/qa/cppunit/view.cxx
@@ -0,0 +1,64 @@
+/* -*- 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 <test/unoapi_test.hxx>
+
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <sfx2/app.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <svl/itemset.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/bindings.hxx>
+
+using namespace com::sun::star;
+
+/// Covers sfx2/source/view/ fixes.
+class Sfx2ViewTest : public UnoApiTest
+{
+public:
+ Sfx2ViewTest()
+ : UnoApiTest("/sfx2/qa/cppunit/data/")
+ {
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(Sfx2ViewTest, testReloadPage)
+{
+ // Load a document, which has 2 pages.
+ loadFromFile(u"reload-page.odg");
+
+ // Reload, and request to start on page 2.
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ SfxAllItemSet aSet(SfxGetpApp()->GetPool());
+ aSet.Put(SfxInt32Item(SID_PAGE_NUMBER, 1));
+ SfxRequest aReq(SID_RELOAD, SfxCallMode::SLOT, aSet);
+ pFrame->ExecReload_Impl(aReq);
+ uno::Reference<frame::XModel> xModel = SfxObjectShell::Current()->GetBaseModel();
+ mxComponent = xModel;
+
+ // Check the current page after reload.
+ uno::Reference<drawing::XDrawView> xController(xModel->getCurrentController(), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPage(xController->getCurrentPage(), uno::UNO_QUERY);
+ sal_Int32 nPage{};
+ xPage->getPropertyValue("Number") >>= nPage;
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 1
+ // i.e. the document was opened on page 1, not page 2, SID_PAGE_NUMBER was ignored.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), nPage);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */