sfx2/JunitTest_sfx2_complex.mk               |    3 
 sfx2/qa/complex/sfx2/DocumentProperties.java |  516 ---------------------------
 sfx2/qa/complex/sfx2/tools/TestDocument.java |   34 -
 sfx2/qa/cppunit/test_misc.cxx                |  406 +++++++++++++++++++++
 4 files changed, 406 insertions(+), 553 deletions(-)

New commits:
commit 5aea0dd59cf15c0f93d432aa722c1e0e1df703e4
Author:     Xisco Fauli <[email protected]>
AuthorDate: Mon Sep 23 16:32:16 2024 +0200
Commit:     Xisco Fauli <[email protected]>
CommitDate: Tue Sep 24 08:43:56 2024 +0200

    sfx2: move DocumentProperties from Java to CppUnittest
    
    Change-Id: I007ff75fb63a20304726a22fa3d949eb3616069e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173820
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/sfx2/JunitTest_sfx2_complex.mk b/sfx2/JunitTest_sfx2_complex.mk
index 504d37e75e6f..7e23021a3ac2 100644
--- a/sfx2/JunitTest_sfx2_complex.mk
+++ b/sfx2/JunitTest_sfx2_complex.mk
@@ -31,11 +31,9 @@ $(eval $(call gb_JunitTest_use_jars,sfx2_complex,\
 ))
 
 $(eval $(call gb_JunitTest_add_sourcefiles,sfx2_complex,\
-    sfx2/qa/complex/sfx2/DocumentProperties \
     sfx2/qa/complex/sfx2/GlobalEventBroadcaster \
     sfx2/qa/complex/sfx2/UndoManager \
     sfx2/qa/complex/sfx2/DocumentEvents \
-    sfx2/qa/complex/sfx2/tools/TestDocument \
     sfx2/qa/complex/sfx2/tools/WriterHelper \
     sfx2/qa/complex/sfx2/undo/CalcDocumentTest \
     sfx2/qa/complex/sfx2/undo/ChartDocumentTest \
@@ -48,7 +46,6 @@ $(eval $(call gb_JunitTest_add_sourcefiles,sfx2_complex,\
 ))
 
 $(eval $(call gb_JunitTest_add_classes,sfx2_complex,\
-    complex.sfx2.DocumentProperties \
     complex.sfx2.DocumentEvents \
     complex.sfx2.UndoManager \
 ))
diff --git a/sfx2/qa/complex/sfx2/DocumentProperties.java 
b/sfx2/qa/complex/sfx2/DocumentProperties.java
deleted file mode 100644
index fe830f118d6d..000000000000
--- a/sfx2/qa/complex/sfx2/DocumentProperties.java
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * 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.sfx2;
-
-
-import complex.sfx2.tools.TestDocument;
-import com.sun.star.uno.UnoRuntime;
-import com.sun.star.uno.XComponentContext;
-import com.sun.star.lang.XInitialization;
-
-import com.sun.star.lang.XMultiServiceFactory;
-import com.sun.star.lang.Locale;
-import com.sun.star.lang.EventObject;
-import com.sun.star.util.Date;
-import com.sun.star.util.DateTime;
-import com.sun.star.util.Time;
-import com.sun.star.util.Duration;
-import com.sun.star.util.XModifyListener;
-import com.sun.star.util.XModifyBroadcaster;
-import com.sun.star.beans.XPropertyContainer;
-import com.sun.star.beans.XPropertySet;
-import com.sun.star.beans.PropertyValue;
-import com.sun.star.beans.NamedValue;
-import com.sun.star.beans.PropertyAttribute;
-import com.sun.star.beans.UnknownPropertyException;
-import com.sun.star.beans.IllegalTypeException;
-
-import com.sun.star.document.XDocumentProperties;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.openoffice.test.OfficeConnection;
-import static org.junit.Assert.*;
-
-/**
- * Test case for the service com.sun.star.document.DocumentProperties.
- * Currently, this service is implemented in
- * sfx2/source/doc/SfxDocumentMetaData.cxx.
- *
- */
-public class DocumentProperties
-{
-    @After public void cleanup() {
-                // nothing to do
-    }
-
-    // for testing modifications
-    private class Listener implements XModifyListener {
-        private boolean m_Called;
-
-        Listener() {
-            m_Called = false;
-        }
-
-        private boolean reset() {
-            boolean oldCalled = m_Called;
-            m_Called = false;
-            return oldCalled;
-        }
-
-        public void modified(EventObject e) {
-            m_Called = true;
-        }
-
-        public void disposing(EventObject e) {
-        }
-    }
-
-    @Test public void check() throws Exception
-    {
-        XMultiServiceFactory xMSF = getMSF();
-        assertNotNull("could not create MultiServiceFactory.", xMSF);
-        XPropertySet xPropertySet = 
UnoRuntime.queryInterface(XPropertySet.class, xMSF);
-        Object defaultCtx = xPropertySet.getPropertyValue("DefaultContext");
-        XComponentContext xContext = 
UnoRuntime.queryInterface(XComponentContext.class, defaultCtx);
-        assertNotNull("could not get component context.", xContext);
-
-        // TODO: Path to temp
-        String temp = util.utils.getOfficeTemp/*Dir*/(xMSF);
-        System.out.println("tempdir: " + temp);
-
-        PropertyValue[] noArgs = { };
-        PropertyValue mimetype = new PropertyValue();
-        mimetype.Name = "MediaType";
-        mimetype.Value = "application/vnd.oasis.opendocument.text";
-        PropertyValue[] mimeArgs = { mimetype };
-        PropertyValue cfile = new PropertyValue();
-        cfile.Name = "URL";
-        cfile.Value = temp + "EMPTY.odt";
-        PropertyValue[] mimeEmptyArgs = { mimetype, cfile };
-
-        System.out.println("Creating service DocumentProperties...");
-
-        Object oDP =
-            xMSF.createInstance("com.sun.star.document.DocumentProperties");
-        XDocumentProperties xDP = 
UnoRuntime.queryInterface(XDocumentProperties.class, oDP);
-
-        System.out.println("...done");
-
-
-        System.out.println("Checking initialize ...");
-
-        XDocumentProperties xDP2 = 
UnoRuntime.queryInterface(XDocumentProperties.class, 
xMSF.createInstance("com.sun.star.document.DocumentProperties"));
-        XInitialization xInit = 
UnoRuntime.queryInterface(XInitialization.class, xDP2);
-        xInit.initialize(new Object[] { });
-
-        System.out.println("...done");
-
-        System.out.println("Checking storing default-initialized meta data 
...");
-
-        xDP2.storeToMedium("", mimeEmptyArgs);
-
-        System.out.println("...done");
-
-        System.out.println("Checking loading default-initialized meta data 
...");
-
-        xDP2.loadFromMedium("", mimeEmptyArgs);
-        assertEquals("Author", "", xDP2.getAuthor());
-
-        System.out.println("...done");
-
-        System.out.println("Checking loading from test document...");
-
-        String file = TestDocument.getUrl("TEST.odt");
-        xDP.loadFromMedium(file, noArgs);
-/*            XInputStream xStream =
-                new StreamSimulator("./testdocuments/TEST.odt", true, param);
-            Object oSF =
-                xMSF.createInstance("com.sun.star.embed.StorageFactory");
-            XSingleServiceFactory xSF = (XSingleServiceFactory)
-                UnoRuntime.queryInterface(XSingleServiceFactory.class, oSF);
-            Object oStor = xSF.createInstanceWithArguments(
-                new Object[] { xStream });
-            XStorage xStor = (XStorage) UnoRuntime.queryInterface(
-                XStorage.class, oStor);
-            xDP.loadFromStorage(xStor);*/
-
-        System.out.println("...done");
-
-        System.out.println("Checking meta-data import...");
-
-        assertEquals("Author", "Karl-Heinz Mustermann", xDP.getAuthor());
-        assertEquals(
-            "Generator",
-            "StarOffice/8$Solaris_x86 
OpenOffice.org_project/680m232$Build-9227",
-            xDP.getGenerator());
-        assertEquals("CreationDate", 2007, xDP.getCreationDate().Year);
-        assertEquals("Title", "Urgent Memo", xDP.getTitle());
-        assertEquals("Subject", "Wichtige Mitteilung", xDP.getSubject());
-        assertEquals(
-            "Description",
-            "Modern internal company memorandum in full-blocked style",
-            xDP.getDescription());
-        assertEquals(
-            "ModifiedBy", "Karl-Heinz Mustermann", xDP.getModifiedBy());
-        assertEquals(
-            "ModificationDate", 10, xDP.getModificationDate().Month);
-        assertEquals(
-            "PrintedBy", "Karl-Heinz Mustermann", xDP.getPrintedBy());
-        assertEquals("PrintDate", 29, xDP.getPrintDate().Day);
-        assertEquals("TemplateName", "Modern Memo", xDP.getTemplateName());
-        assertTrue("TemplateURL",
-            xDP.getTemplateURL().endsWith("memmodern.ott"));
-        assertEquals("TemplateDate", 17, xDP.getTemplateDate().Hours);
-        assertTrue(
-            "AutoloadURL", xDP.getAutoloadURL().endsWith("/TEST.odt"));
-        assertEquals("AutoloadSecs", 0, xDP.getAutoloadSecs());
-        assertEquals("DefaultTarget", "_blank", xDP.getDefaultTarget());
-        assertEquals("EditingCycles", 3, xDP.getEditingCycles());
-        assertEquals("EditingDuration", 320, xDP.getEditingDuration());
-
-        String[] kws = xDP.getKeywords();
-        assertTrue("Keywords", fromArray(kws).containsAll(
-                fromArray(new Object[] { "Asien", "Memo", "Reis" })));
-
-        NamedValue[] ds = xDP.getDocumentStatistics();
-        assertTrue("DocumentStatistics:WordCount", containsNV(ds,
-                    new NamedValue("WordCount", Integer.valueOf(23))));
-        assertTrue("DocumentStatistics:PageCount", containsNV(ds,
-                    new NamedValue("PageCount", Integer.valueOf(1))));
-
-        XPropertyContainer udpc = xDP.getUserDefinedProperties();
-        XPropertySet udps = UnoRuntime.queryInterface( XPropertySet.class, 
udpc );
-        assertEquals(
-            "UserDefined 1", "Dies ist ein wichtiger Hinweis",
-            udps.getPropertyValue("Hinweis"));
-        assertEquals(
-            "UserDefined 2", "Kann Spuren von N\u00FCssen enthalten",
-            udps.getPropertyValue("Warnung"));
-
-        System.out.println("...done");
-
-        System.out.println("Checking meta-data updates...");
-
-        String str;
-        DateTime dt = new DateTime();
-        Locale l = new Locale();
-        int i;
-
-        str = "me";
-        xDP.setAuthor(str);
-        assertEquals("setAuthor", str, xDP.getAuthor());
-        str = "the computa";
-        xDP.setGenerator(str);
-        assertEquals("setGenerator", str, xDP.getGenerator());
-        dt.Year = 2038;
-        dt.Month = 1;
-        dt.Day = 1;
-        xDP.setCreationDate(dt);
-        assertEquals(
-            "setCreationDate", dt.Year, xDP.getCreationDate().Year);
-        str = "El t'itulo";
-        xDP.setTitle(str);
-        assertEquals("setTitle", str, xDP.getTitle());
-        str = "Ein verkommenes Subjekt";
-        xDP.setSubject(str);
-        assertEquals("setSubject", str, xDP.getSubject());
-        str = "Este descripci'on no es importante";
-        xDP.setDescription(str);
-        assertEquals("setDescription", str, xDP.getDescription());
-        l.Language = "en";
-        l.Country = "GB";
-        xDP.setLanguage(l);
-        Locale l2 = xDP.getLanguage();
-        assertEquals("setLanguage Lang", l.Language, l2.Language);
-        assertEquals("setLanguage Cty", l.Country, l2.Country);
-        str = "myself";
-        xDP.setModifiedBy(str);
-        assertEquals("setModifiedBy", str, xDP.getModifiedBy());
-        dt.Year = 2042;
-        xDP.setModificationDate(dt);
-        assertEquals(
-            "setModificationDate", dt.Year, xDP.getModificationDate().Year);
-        str = "i did not do it";
-        xDP.setPrintedBy(str);
-        assertEquals("setPrintedBy", str, xDP.getPrintedBy());
-        dt.Year = 2024;
-        xDP.setPrintDate(dt);
-        assertEquals("setPrintDate", dt.Year, xDP.getPrintDate().Year);
-        str = "blah";
-        xDP.setTemplateName(str);
-        assertEquals("setTemplateName", str, xDP.getTemplateName());
-        str = "gopher://some-hole-in-the-ground/";;
-        xDP.setTemplateURL(str);
-        assertEquals("setTemplateURL", str, xDP.getTemplateURL());
-        dt.Year = 2043;
-        xDP.setTemplateDate(dt);
-        assertEquals(
-            "setTemplateDate", dt.Year, xDP.getTemplateDate().Year);
-        str = "http://nowhere/";;
-        xDP.setAutoloadURL(str);
-        assertEquals("setAutoloadURL", str, xDP.getAutoloadURL());
-        i = 3661; // this might not work (due to conversion via double...)
-        xDP.setAutoloadSecs(i);
-        assertEquals("setAutoloadSecs", i, xDP.getAutoloadSecs());
-        str = "_blank";
-        xDP.setDefaultTarget(str);
-        assertEquals("setDefaultTarget", str, xDP.getDefaultTarget());
-        i = 42;
-        xDP.setEditingCycles((short) i);
-        assertEquals("setEditingCycles", i, xDP.getEditingCycles());
-        i = 84;
-        xDP.setEditingDuration(i);
-        assertEquals("setEditingDuration", i, xDP.getEditingDuration());
-        str = "";
-
-        String[] kws2 = new String[] {
-            "keywordly", "keywordlike", "keywordalicious" };
-        xDP.setKeywords(kws2);
-        kws = xDP.getKeywords();
-        assertTrue("setKeywords", fromArray(kws).containsAll(fromArray(kws2)));
-
-        NamedValue[] ds2 = new NamedValue[] {
-                new NamedValue("SyllableCount", Integer.valueOf(9)),
-                new NamedValue("FrameCount", Integer.valueOf(2)),
-                new NamedValue("SentenceCount", Integer.valueOf(7)) };
-        xDP.setDocumentStatistics(ds2);
-        ds = xDP.getDocumentStatistics();
-        assertTrue("setDocumentStatistics:SyllableCount", containsNV(ds,
-                    new NamedValue("SyllableCount", Integer.valueOf(9))));
-        assertTrue("setDocumentStatistics:FrameCount", containsNV(ds,
-                    new NamedValue("FrameCount", Integer.valueOf(2))));
-        assertTrue("setDocumentStatistics:SentenceCount", containsNV(ds,
-                    new NamedValue("SentenceCount", Integer.valueOf(7))));
-
-        System.out.println("...done");
-
-        System.out.println("Checking user-defined meta-data updates...");
-
-        // actually, this tests the PropertyBag service
-        // but maybe the DocumentProperties service will be implemented
-        // differently some day...
-        boolean b = true;
-        double d = 3.1415;
-        // note that Time is only supported for backward compatibility!
-        Time t = new Time();
-        t.Hours = 1;
-        t.Minutes = 16;
-        Date date = new Date();
-        date.Year = 2071;
-        date.Month = 2;
-        date.Day = 3;
-        dt.Year = 2065;
-        Duration dur = new Duration();
-        dur.Negative = true;
-        dur.Years = 1001;
-        dur.Months = 999;
-        dur.Days = 888;
-        dur.Hours = 777;
-        dur.Minutes = 666;
-        dur.Seconds = 555;
-        dur.NanoSeconds = 444444444;
-
-        udpc.addProperty("Frobnicate", PropertyAttribute.REMOVABLE, b);
-        udpc.addProperty("FrobDuration", PropertyAttribute.REMOVABLE, dur);
-        udpc.addProperty("FrobDuration2", PropertyAttribute.REMOVABLE, t);
-        udpc.addProperty("FrobEndDate", PropertyAttribute.REMOVABLE, date);
-        udpc.addProperty("FrobStartTime", PropertyAttribute.REMOVABLE, dt);
-        udpc.addProperty("Pi", PropertyAttribute.REMOVABLE, Double.valueOf(d));
-        udpc.addProperty("Foo", PropertyAttribute.REMOVABLE, "bar");
-        udpc.addProperty("Removed", PropertyAttribute.REMOVABLE, "bar");
-        // #i94175#: empty property name is valid ODF 1.1
-        udpc.addProperty("", PropertyAttribute.REMOVABLE, "eeeeek");
-        try {
-            udpc.removeProperty("Info 1");
-            udpc.removeProperty("Removed");
-        } catch (UnknownPropertyException e) {
-            fail("removeProperty failed");
-        }
-
-        try {
-            udpc.addProperty("Forbidden", PropertyAttribute.REMOVABLE,
-                new String[] { "foo", "bar" });
-            fail("inserting value of non-supported type did not fail");
-        } catch (IllegalTypeException e) {
-            // ignore
-        }
-
-        assertEquals(
-            "UserDefined bool", b, udps.getPropertyValue("Frobnicate"));
-        assertTrue("UserDefined duration", eqDuration(dur, (Duration)
-                udps.getPropertyValue("FrobDuration")));
-        assertTrue("UserDefined time", eqTime(t, (Time)
-                udps.getPropertyValue("FrobDuration2")));
-        assertTrue("UserDefined date", eqDate(date, (Date)
-                udps.getPropertyValue("FrobEndDate")));
-        assertTrue("UserDefined datetime", eqDateTime(dt, (DateTime)
-                udps.getPropertyValue("FrobStartTime")));
-        assertEquals("UserDefined float", d, udps.getPropertyValue("Pi"));
-        assertEquals(
-            "UserDefined string", "bar", udps.getPropertyValue("Foo"));
-        assertEquals(
-            "UserDefined empty name", "eeeeek", udps.getPropertyValue(""));
-
-        try {
-            udps.getPropertyValue("Removed");
-            fail("UserDefined remove didn't");
-        } catch (UnknownPropertyException e) {
-            // ok
-        }
-
-        System.out.println("...done");
-
-        System.out.println("Checking storing meta-data to file...");
-
-        xDP.storeToMedium(temp + "TEST.odt", mimeArgs);
-
-        System.out.println("...done");
-
-        System.out.println("Checking loading meta-data from stored file...");
-
-        xDP.loadFromMedium(temp + "TEST.odt", noArgs);
-
-        System.out.println("...done");
-
-        System.out.println("Checking user-defined meta-data from stored 
file...");
-
-        udpc = xDP.getUserDefinedProperties();
-        udps = UnoRuntime.queryInterface( XPropertySet.class, udpc );
-
-        assertEquals(
-            "UserDefined bool", b, udps.getPropertyValue("Frobnicate"));
-        assertTrue("UserDefined duration", eqDuration(dur, (Duration)
-                udps.getPropertyValue("FrobDuration")));
-        // this is now a Duration!
-        Duration t_dur = new Duration(false, (short)0, (short)0, (short)0,
-                t.Hours, t.Minutes, t.Seconds,
-                t.NanoSeconds);
-        assertTrue("UserDefined time", eqDuration(t_dur, (Duration)
-                udps.getPropertyValue("FrobDuration2")));
-        assertTrue("UserDefined date", eqDate(date, (Date)
-                udps.getPropertyValue("FrobEndDate")));
-        assertTrue("UserDefined datetime", eqDateTime(dt, (DateTime)
-                udps.getPropertyValue("FrobStartTime")));
-        assertEquals("UserDefined float", d, udps.getPropertyValue("Pi"));
-        assertEquals(
-            "UserDefined string", "bar", udps.getPropertyValue("Foo"));
-
-        try {
-            udps.getPropertyValue("Removed");
-            fail("UserDefined remove didn't");
-        } catch (UnknownPropertyException e) {
-            // ok
-        }
-
-        System.out.println("...done");
-
-        System.out.println("Checking notification listener interface...");
-
-        Listener listener = new Listener();
-        XModifyBroadcaster xMB = UnoRuntime.queryInterface( 
XModifyBroadcaster.class, xDP );
-        xMB.addModifyListener(listener);
-        xDP.setAuthor("not me");
-        assertTrue("Listener Author", listener.reset());
-        udpc.addProperty("Listener", PropertyAttribute.REMOVABLE, "foo");
-        assertTrue("Listener UserDefined Add", listener.reset());
-        udps.setPropertyValue("Listener", "bar");
-        assertTrue("Listener UserDefined Set", listener.reset());
-        udpc.removeProperty("Listener");
-        assertTrue("Listener UserDefined Remove", listener.reset());
-        xMB.removeModifyListener(listener);
-        udpc.addProperty("Listener2", PropertyAttribute.REMOVABLE, "foo");
-        assertTrue("Removed Listener UserDefined Add", !listener.reset());
-
-        System.out.println("...done");
-    }
-
-    // grrr...
-    boolean eqDateTime(DateTime a, DateTime b) {
-        return a.Year == b.Year && a.Month == b.Month && a.Day == b.Day
-            && a.Hours == b.Hours && a.Minutes == b.Minutes
-            && a.Seconds == b.Seconds
-            && a.NanoSeconds == b.NanoSeconds;
-    }
-
-    boolean eqDate(Date a, Date b) {
-        return a.Year == b.Year && a.Month == b.Month && a.Day == b.Day;
-    }
-
-    boolean eqTime(Time a, Time b) {
-        return a.Hours == b.Hours && a.Minutes == b.Minutes
-            && a.Seconds == b.Seconds
-            && a.NanoSeconds == b.NanoSeconds;
-    }
-
-    boolean eqDuration(Duration a, Duration b) {
-        return a.Years == b.Years && a.Months == b.Months && a.Days == b.Days
-            && a.Hours == b.Hours && a.Minutes == b.Minutes
-            && a.Seconds == b.Seconds
-            && a.NanoSeconds == b.NanoSeconds
-            && a.Negative == b.Negative;
-    }
-
-    java.util.Collection<Object> fromArray(Object[] os) {
-        java.util.Collection<Object> ret = new java.util.HashSet<Object>();
-        for (int i = 0; i < os.length; ++i) {
-            ret.add(os[i]);
-        }
-        return ret;
-    }
-
-    // bah, structs do not have proper equals(), and uno.Type is not comparable
-    public static boolean containsNV (NamedValue[] nvs, NamedValue nv) {
-        for (int i = 0; i < nvs.length; ++i) {
-            if (nvs[i].Name.equals(nv.Name) && nvs[i].Value.equals(nv.Value)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private XMultiServiceFactory getMSF()
-    {
-        final XMultiServiceFactory xMSF1 = UnoRuntime.queryInterface( 
XMultiServiceFactory.class, 
connection.getComponentContext().getServiceManager() );
-        return xMSF1;
-    }
-
-    // setup and close connections
-    @BeforeClass public static void setUpConnection() throws Exception {
-        System.out.println( 
"------------------------------------------------------------" );
-        System.out.println( "starting class: " + 
DocumentProperties.class.getName() );
-        System.out.println( 
"------------------------------------------------------------" );
-        connection.setUp();
-    }
-
-    @AfterClass public static void tearDownConnection()
-        throws InterruptedException, com.sun.star.uno.Exception
-    {
-        System.out.println( 
"------------------------------------------------------------" );
-        System.out.println( "finishing class: " + 
DocumentProperties.class.getName() );
-        System.out.println( 
"------------------------------------------------------------" );
-        connection.tearDown();
-    }
-
-    private static final OfficeConnection connection = new OfficeConnection();
-
-}
-
diff --git a/sfx2/qa/complex/sfx2/tools/TestDocument.java 
b/sfx2/qa/complex/sfx2/tools/TestDocument.java
deleted file mode 100644
index 462c97fb99b7..000000000000
--- a/sfx2/qa/complex/sfx2/tools/TestDocument.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.sfx2.tools;
-
-import java.io.File;
-import org.openoffice.test.OfficeFileUrl;
-import org.openoffice.test.Argument;
-
-public final class TestDocument {
-    public static String getUrl(String name) {
-        return OfficeFileUrl.getAbsolute(new File(Argument.get("tdoc"), name));
-    }
-    public static String getPath(String name) {
-        return new File(Argument.get("tdoc"), name).toString();
-    }
-
-    private TestDocument() {}
-}
diff --git a/sfx2/qa/cppunit/test_misc.cxx b/sfx2/qa/cppunit/test_misc.cxx
index 4c842df2a4f7..c32fee011900 100644
--- a/sfx2/qa/cppunit/test_misc.cxx
+++ b/sfx2/qa/cppunit/test_misc.cxx
@@ -16,6 +16,9 @@
 #include <memory>
 
 #include <com/sun/star/beans/Pair.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
 #include <com/sun/star/beans/PropertyState.hpp>
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/document/DocumentProperties.hpp>
@@ -24,6 +27,13 @@
 #include <com/sun/star/frame/XStorable.hpp>
 #include <com/sun/star/text/XTextDocument.hpp>
 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Duration.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
 
 #include <test/unoapixml_test.hxx>
 
@@ -59,6 +69,28 @@ public:
     }
 };
 
+class Listener : public ::cppu::WeakImplHelper<css::util::XModifyListener>
+{
+public:
+    Listener()
+        : bCalled(false)
+    {
+    }
+
+    bool reset()
+    {
+        bool bOld = bCalled;
+        bCalled = false;
+        return bOld;
+    }
+
+private:
+    bool bCalled;
+
+    virtual void SAL_CALL disposing(const lang::EventObject&) noexcept 
override {}
+    virtual void SAL_CALL modified(const lang::EventObject&) noexcept override 
{ bCalled = true; }
+};
+
 CPPUNIT_TEST_FIXTURE(MiscTest, testODFCustomMetadata)
 {
     uno::Reference<document::XDocumentProperties> const xProps(
@@ -81,6 +113,380 @@ CPPUNIT_TEST_FIXTURE(MiscTest, testODFCustomMetadata)
     assertXPathContent(pXmlDoc, 
"/office:document-meta/office:meta/foo:bar/foo:baz"_ostr, u"bar"_ustr);
 }
 
+/**
+ * Test case for the service com.sun.star.document.DocumentProperties.
+ * Currently, this service is implemented in
+ * sfx2/source/doc/SfxDocumentMetaData.cxx.
+ *
+ */
+CPPUNIT_TEST_FIXTURE(MiscTest, testDocumentProperties)
+{
+    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/TEST.odt"));
+    xProps->loadFromMedium(url, uno::Sequence<beans::PropertyValue>());
+    CPPUNIT_ASSERT_EQUAL(u"Karl-Heinz Mustermann"_ustr, xProps->getAuthor());
+    CPPUNIT_ASSERT_EQUAL(u"StarOffice/8$Solaris_x86 
OpenOffice.org_project/680m232$Build-9227"_ustr,
+                         xProps->getGenerator());
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2007), xProps->getCreationDate().Year);
+    CPPUNIT_ASSERT_EQUAL(u"Urgent Memo"_ustr, xProps->getTitle());
+    CPPUNIT_ASSERT_EQUAL(u"Wichtige Mitteilung"_ustr, xProps->getSubject());
+    CPPUNIT_ASSERT_EQUAL(u"Modern internal company memorandum in full-blocked 
style"_ustr,
+                         xProps->getDescription());
+    CPPUNIT_ASSERT_EQUAL(u"Karl-Heinz Mustermann"_ustr, 
xProps->getModifiedBy());
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(10), xProps->getModificationDate().Month);
+    CPPUNIT_ASSERT_EQUAL(u"Karl-Heinz Mustermann"_ustr, 
xProps->getPrintedBy());
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(29), xProps->getPrintDate().Day);
+    CPPUNIT_ASSERT_EQUAL(u"Modern Memo"_ustr, xProps->getTemplateName());
+    CPPUNIT_ASSERT(xProps->getTemplateURL().endsWith("memmodern.ott"));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(17), xProps->getTemplateDate().Hours);
+    CPPUNIT_ASSERT(xProps->getAutoloadURL().endsWith("/TEST.odt"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xProps->getAutoloadSecs());
+    CPPUNIT_ASSERT_EQUAL(u"_blank"_ustr, xProps->getDefaultTarget());
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(3), xProps->getEditingCycles());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(320), xProps->getEditingDuration());
+
+    uno::Sequence<OUString> aKeywords(xProps->getKeywords());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), aKeywords.getLength());
+    CPPUNIT_ASSERT_EQUAL(u"Memo"_ustr, aKeywords[0]);
+    CPPUNIT_ASSERT_EQUAL(u"Asien"_ustr, aKeywords[1]);
+    CPPUNIT_ASSERT_EQUAL(u"Reis"_ustr, aKeywords[2]);
+
+    uno::Sequence<beans::NamedValue> aDocStats = 
xProps->getDocumentStatistics();
+    auto it = std::find_if(std::cbegin(aDocStats), std::cend(aDocStats),
+                           [](const css::beans::NamedValue& val) {
+                               return val.Name == "WordCount" && 
val.Value.get<sal_uInt32>() == 23;
+                           });
+    CPPUNIT_ASSERT(it != std::cend(aDocStats));
+
+    it = std::find_if(std::cbegin(aDocStats), std::cend(aDocStats),
+                      [](const css::beans::NamedValue& val) {
+                          return val.Name == "PageCount" && 
val.Value.get<sal_uInt32>() == 1;
+                      });
+    CPPUNIT_ASSERT(it != std::cend(aDocStats));
+
+    uno::Reference<beans::XPropertyContainer> xUDP = 
xProps->getUserDefinedProperties();
+    uno::Reference<beans::XPropertySet> xPropertySet(xUDP, uno::UNO_QUERY);
+    uno::Any aAny = xPropertySet->getPropertyValue(u"Hinweis"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"Dies ist ein wichtiger Hinweis"_ustr, 
aAny.get<OUString>());
+
+    aAny = xPropertySet->getPropertyValue(u"Warnung"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"Kann Spuren von N\u00FCssen enthalten"_ustr, 
aAny.get<OUString>());
+
+    xProps->setAuthor(u"me"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"me"_ustr, xProps->getAuthor());
+
+    xProps->setGenerator(u"the computa"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"the computa"_ustr, xProps->getGenerator());
+
+    css::util::DateTime aDateTime;
+    aDateTime.Day = 1;
+    aDateTime.Month = 1;
+    aDateTime.Year = 2038;
+    xProps->setCreationDate(aDateTime);
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2038), xProps->getCreationDate().Year);
+
+    xProps->setTitle(u"El t'itulo"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"El t'itulo"_ustr, xProps->getTitle());
+
+    xProps->setSubject(u"Ein verkommenes Subjekt"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"Ein verkommenes Subjekt"_ustr, 
xProps->getSubject());
+
+    xProps->setDescription(u"Este descripci'on no es importante"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"Este descripci'on no es importante"_ustr, 
xProps->getDescription());
+
+    lang::Locale aLang;
+    aLang.Language = u"en"_ustr;
+    aLang.Country = u"GB"_ustr;
+
+    xProps->setLanguage(aLang);
+    CPPUNIT_ASSERT_EQUAL(aLang.Language, xProps->getLanguage().Language);
+    CPPUNIT_ASSERT_EQUAL(aLang.Country, xProps->getLanguage().Country);
+
+    xProps->setModifiedBy(u"myself"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"myself"_ustr, xProps->getModifiedBy());
+
+    aDateTime.Year = 2042;
+    xProps->setModificationDate(aDateTime);
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2042), xProps->getModificationDate().Year);
+
+    xProps->setPrintedBy(u"i did not do it"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"i did not do it"_ustr, xProps->getPrintedBy());
+
+    aDateTime.Year = 2024;
+    xProps->setPrintDate(aDateTime);
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2024), xProps->getPrintDate().Year);
+
+    xProps->setTemplateName(u"blah"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"blah"_ustr, xProps->getTemplateName());
+
+    xProps->setTemplateURL(u"gopher://some-hole-in-the-ground/"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"gopher://some-hole-in-the-ground/"_ustr, 
xProps->getTemplateURL());
+
+    aDateTime.Year = 2043;
+    xProps->setTemplateDate(aDateTime);
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2043), xProps->getTemplateDate().Year);
+
+    xProps->setAutoloadURL(u"http://nowhere/"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"http://nowhere/"_ustr, xProps->getAutoloadURL());
+
+    xProps->setAutoloadSecs(3661);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3661), xProps->getAutoloadSecs());
+
+    xProps->setDefaultTarget(u"_blank"_ustr);
+    CPPUNIT_ASSERT_EQUAL(u"_blank"_ustr, xProps->getDefaultTarget());
+
+    xProps->setEditingCycles(42);
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(42), xProps->getEditingCycles());
+
+    xProps->setEditingDuration(84);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(84), xProps->getEditingDuration());
+
+    uno::Sequence<OUString> aKeywords2{ u"keywordly"_ustr, u"keywordlike"_ustr,
+                                        u"keywordalicious"_ustr };
+    xProps->setKeywords(aKeywords2);
+    aKeywords = xProps->getKeywords();
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), aKeywords.getLength());
+    CPPUNIT_ASSERT_EQUAL(u"keywordly"_ustr, aKeywords[0]);
+    CPPUNIT_ASSERT_EQUAL(u"keywordlike"_ustr, aKeywords[1]);
+    CPPUNIT_ASSERT_EQUAL(u"keywordalicious"_ustr, aKeywords[2]);
+
+    uno::Sequence<beans::NamedValue> aDocStats2{ { u"SyllableCount"_ustr, 
uno::Any(sal_Int16(9)) },
+                                                 { u"FrameCount"_ustr, 
uno::Any(sal_Int16(2)) },
+                                                 { u"SentenceCount"_ustr,
+                                                   uno::Any(sal_Int16(7)) } };
+
+    xProps->setDocumentStatistics(aDocStats2);
+    aDocStats = xProps->getDocumentStatistics();
+
+    it = std::find_if(std::cbegin(aDocStats), std::cend(aDocStats),
+                      [](const css::beans::NamedValue& val) {
+                          return val.Name == "SyllableCount" && 
val.Value.get<sal_uInt32>() == 9;
+                      });
+    CPPUNIT_ASSERT(it != std::cend(aDocStats));
+
+    it = std::find_if(std::cbegin(aDocStats), std::cend(aDocStats),
+                      [](const css::beans::NamedValue& val) {
+                          return val.Name == "FrameCount" && 
val.Value.get<sal_uInt32>() == 2;
+                      });
+    CPPUNIT_ASSERT(it != std::cend(aDocStats));
+
+    it = std::find_if(std::cbegin(aDocStats), std::cend(aDocStats),
+                      [](const css::beans::NamedValue& val) {
+                          return val.Name == "SentenceCount" && 
val.Value.get<sal_uInt32>() == 7;
+                      });
+    CPPUNIT_ASSERT(it != std::cend(aDocStats));
+
+    // actually, this tests the PropertyBag service
+    // but maybe the DocumentProperties service will be implemented
+    // differently some day...
+
+    // note that Time is only supported for backward compatibility!
+    css::util::Time aTime;
+    aTime.Hours = 1;
+    aTime.Minutes = 16;
+
+    css::util::Date aDate;
+    aDate.Year = 2071;
+    aDate.Month = 2;
+    aDate.Day = 3;
+
+    aDateTime.Year = 2065;
+
+    css::util::Duration aDur;
+    aDur.Negative = true;
+    aDur.Years = 1001;
+    aDur.Months = 999;
+    aDur.Days = 888;
+    aDur.Hours = 777;
+    aDur.Minutes = 666;
+    aDur.Seconds = 555;
+    aDur.NanoSeconds = 444444444;
+
+    xUDP->addProperty("Frobnicate", beans::PropertyAttribute::REMOVABLE, 
uno::Any(true));
+    xUDP->addProperty("FrobDuration", beans::PropertyAttribute::REMOVABLE, 
uno::Any(aDur));
+    xUDP->addProperty("FrobDuration2", beans::PropertyAttribute::REMOVABLE, 
uno::Any(aTime));
+    xUDP->addProperty("FrobEndDate", beans::PropertyAttribute::REMOVABLE, 
uno::Any(aDate));
+    xUDP->addProperty("FrobStartTime", beans::PropertyAttribute::REMOVABLE, 
uno::Any(aDateTime));
+    xUDP->addProperty("Pi", beans::PropertyAttribute::REMOVABLE, 
uno::Any(3.1415));
+    xUDP->addProperty("Foo", beans::PropertyAttribute::REMOVABLE, 
uno::Any(u"bar"_ustr));
+    xUDP->addProperty("Removed", beans::PropertyAttribute::REMOVABLE, 
uno::Any(u"bar"_ustr));
+    // #i94175#: empty property name is valid ODF 1.1
+    xUDP->addProperty("", beans::PropertyAttribute::REMOVABLE, 
uno::Any(u"eeeeek"_ustr));
+
+    try
+    {
+        xUDP->removeProperty(u"Info 1"_ustr);
+        xUDP->removeProperty(u"Removed"_ustr);
+    }
+    catch (beans::UnknownPropertyException&)
+    {
+        CPPUNIT_FAIL("removeProperty failed");
+    }
+
+    try
+    {
+        xUDP->addProperty("Forbidden", beans::PropertyAttribute::REMOVABLE,
+                          uno::Any(uno::Sequence<OUString>{ u"foo"_ustr, 
u"bar"_ustr }));
+        CPPUNIT_FAIL("inserting value of non-supported type did not fail");
+    }
+    catch (beans::IllegalTypeException&)
+    {
+    }
+
+    aAny = xPropertySet->getPropertyValue(u"Frobnicate"_ustr);
+    CPPUNIT_ASSERT_EQUAL(true, aAny.get<bool>());
+
+    aAny = xPropertySet->getPropertyValue(u"FrobDuration"_ustr);
+    css::util::Duration aDur2 = aAny.get<css::util::Duration>();
+    CPPUNIT_ASSERT_EQUAL(aDur.Negative, aDur2.Negative);
+    CPPUNIT_ASSERT_EQUAL(aDur.Years, aDur2.Years);
+    CPPUNIT_ASSERT_EQUAL(aDur.Months, aDur2.Months);
+    CPPUNIT_ASSERT_EQUAL(aDur.Days, aDur2.Days);
+    CPPUNIT_ASSERT_EQUAL(aDur.Hours, aDur2.Hours);
+    CPPUNIT_ASSERT_EQUAL(aDur.Minutes, aDur2.Minutes);
+    CPPUNIT_ASSERT_EQUAL(aDur.Seconds, aDur2.Seconds);
+    CPPUNIT_ASSERT_EQUAL(aDur.NanoSeconds, aDur2.NanoSeconds);
+
+    aAny = xPropertySet->getPropertyValue(u"FrobDuration2"_ustr);
+    css::util::Time aTime2 = aAny.get<css::util::Time>();
+    CPPUNIT_ASSERT_EQUAL(aTime.Hours, aTime2.Hours);
+    CPPUNIT_ASSERT_EQUAL(aTime.Minutes, aTime2.Minutes);
+    CPPUNIT_ASSERT_EQUAL(aTime.Seconds, aTime2.Seconds);
+    CPPUNIT_ASSERT_EQUAL(aTime.NanoSeconds, aTime2.NanoSeconds);
+
+    aAny = xPropertySet->getPropertyValue(u"FrobEndDate"_ustr);
+    css::util::Date aDate2 = aAny.get<css::util::Date>();
+    CPPUNIT_ASSERT_EQUAL(aDate.Day, aDate2.Day);
+    CPPUNIT_ASSERT_EQUAL(aDate.Month, aDate2.Month);
+    CPPUNIT_ASSERT_EQUAL(aDate.Year, aDate2.Year);
+
+    aAny = xPropertySet->getPropertyValue(u"FrobStartTime"_ustr);
+    css::util::DateTime aDateTime2 = aAny.get<css::util::DateTime>();
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Year, aDateTime2.Year);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Month, aDateTime2.Month);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Day, aDateTime2.Day);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Hours, aDateTime2.Hours);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Minutes, aDateTime2.Minutes);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Seconds, aDateTime2.Seconds);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.NanoSeconds, aDateTime2.NanoSeconds);
+
+    aAny = xPropertySet->getPropertyValue(u"Pi"_ustr);
+    double aPi = aAny.get<double>();
+    CPPUNIT_ASSERT_EQUAL(3.1415, aPi);
+
+    aAny = xPropertySet->getPropertyValue(u"Foo"_ustr);
+    OUString aFoo = aAny.get<OUString>();
+    CPPUNIT_ASSERT_EQUAL(u"bar"_ustr, aFoo);
+
+    aAny = xPropertySet->getPropertyValue(u""_ustr);
+    OUString aEmpty = aAny.get<OUString>();
+    CPPUNIT_ASSERT_EQUAL(u"eeeeek"_ustr, aEmpty);
+
+    try
+    {
+        xPropertySet->getPropertyValue(u"Removed"_ustr);
+        CPPUNIT_FAIL("UserDefined remove didn't");
+    }
+    catch (beans::UnknownPropertyException&)
+    {
+    }
+
+    uno::Sequence<beans::PropertyValue> mimeArgs({ beans::PropertyValue(
+        u"MediaType"_ustr, -1, 
uno::Any(u"application/vnd.oasis.opendocument.text"_ustr),
+        beans::PropertyState_DIRECT_VALUE) });
+    xProps->storeToMedium(maTempFile.GetURL(), mimeArgs);
+
+    xProps->loadFromMedium(maTempFile.GetURL(), 
uno::Sequence<beans::PropertyValue>());
+
+    xUDP = xProps->getUserDefinedProperties();
+    xPropertySet.set(xUDP, uno::UNO_QUERY);
+
+    aAny = xPropertySet->getPropertyValue(u"Frobnicate"_ustr);
+    CPPUNIT_ASSERT_EQUAL(true, aAny.get<bool>());
+
+    aAny = xPropertySet->getPropertyValue(u"FrobDuration"_ustr);
+    aDur2 = aAny.get<css::util::Duration>();
+    CPPUNIT_ASSERT_EQUAL(aDur.Negative, aDur2.Negative);
+    CPPUNIT_ASSERT_EQUAL(aDur.Years, aDur2.Years);
+    CPPUNIT_ASSERT_EQUAL(aDur.Months, aDur2.Months);
+    CPPUNIT_ASSERT_EQUAL(aDur.Days, aDur2.Days);
+    CPPUNIT_ASSERT_EQUAL(aDur.Hours, aDur2.Hours);
+    CPPUNIT_ASSERT_EQUAL(aDur.Minutes, aDur2.Minutes);
+    CPPUNIT_ASSERT_EQUAL(aDur.Seconds, aDur2.Seconds);
+    CPPUNIT_ASSERT_EQUAL(aDur.NanoSeconds, aDur2.NanoSeconds);
+
+    css::util::Duration aDur3(false, 0, 0, 0, aTime.Hours, aTime.Minutes, 
aTime.Seconds,
+                              aTime.NanoSeconds);
+    // this is now a Duration!
+    aAny = xPropertySet->getPropertyValue(u"FrobDuration2"_ustr);
+    aDur2 = aAny.get<css::util::Duration>();
+    CPPUNIT_ASSERT_EQUAL(aDur3.Negative, aDur2.Negative);
+    CPPUNIT_ASSERT_EQUAL(aDur3.Years, aDur2.Years);
+    CPPUNIT_ASSERT_EQUAL(aDur3.Months, aDur2.Months);
+    CPPUNIT_ASSERT_EQUAL(aDur3.Days, aDur2.Days);
+    CPPUNIT_ASSERT_EQUAL(aDur3.Hours, aDur2.Hours);
+    CPPUNIT_ASSERT_EQUAL(aDur3.Minutes, aDur2.Minutes);
+    CPPUNIT_ASSERT_EQUAL(aDur3.Seconds, aDur2.Seconds);
+    CPPUNIT_ASSERT_EQUAL(aDur3.NanoSeconds, aDur2.NanoSeconds);
+
+    aAny = xPropertySet->getPropertyValue(u"FrobEndDate"_ustr);
+    aDate2 = aAny.get<css::util::Date>();
+    CPPUNIT_ASSERT_EQUAL(aDate.Day, aDate2.Day);
+    CPPUNIT_ASSERT_EQUAL(aDate.Month, aDate2.Month);
+    CPPUNIT_ASSERT_EQUAL(aDate.Year, aDate2.Year);
+
+    aAny = xPropertySet->getPropertyValue(u"FrobStartTime"_ustr);
+    aDateTime2 = aAny.get<css::util::DateTime>();
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Year, aDateTime2.Year);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Month, aDateTime2.Month);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Day, aDateTime2.Day);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Hours, aDateTime2.Hours);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Minutes, aDateTime2.Minutes);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.Seconds, aDateTime2.Seconds);
+    CPPUNIT_ASSERT_EQUAL(aDateTime.NanoSeconds, aDateTime2.NanoSeconds);
+
+    aAny = xPropertySet->getPropertyValue(u"Pi"_ustr);
+    aPi = aAny.get<double>();
+    CPPUNIT_ASSERT_EQUAL(3.1415, aPi);
+
+    aAny = xPropertySet->getPropertyValue(u"Foo"_ustr);
+    aFoo = aAny.get<OUString>();
+    CPPUNIT_ASSERT_EQUAL(u"bar"_ustr, aFoo);
+
+    aAny = xPropertySet->getPropertyValue(u""_ustr);
+    aEmpty = aAny.get<OUString>();
+    CPPUNIT_ASSERT_EQUAL(u"eeeeek"_ustr, aEmpty);
+
+    try
+    {
+        xPropertySet->getPropertyValue(u"Removed"_ustr);
+        CPPUNIT_FAIL("UserDefined remove didn't");
+    }
+    catch (beans::UnknownPropertyException&)
+    {
+    }
+
+    rtl::Reference<Listener> xListener = new Listener();
+    css::uno::Reference<css::util::XModifyBroadcaster> xBroadcaster(xProps, 
css::uno::UNO_QUERY);
+    xBroadcaster->addModifyListener(xListener);
+    xProps->setAuthor(u"not me"_ustr);
+    CPPUNIT_ASSERT(xListener->reset());
+    xUDP->addProperty(u"Listener"_ustr, beans::PropertyAttribute::REMOVABLE, 
uno::Any(u"foo"_ustr));
+    CPPUNIT_ASSERT(xListener->reset());
+    xPropertySet->setPropertyValue(u"Listener"_ustr, uno::Any(u"bar"_ustr));
+    CPPUNIT_ASSERT(xListener->reset());
+    xUDP->removeProperty(u"Listener"_ustr);
+    CPPUNIT_ASSERT(xListener->reset());
+
+    xBroadcaster->removeModifyListener(xListener);
+    xUDP->addProperty(u"Listener2"_ustr, beans::PropertyAttribute::REMOVABLE,
+                      uno::Any(u"foo"_ustr));
+    CPPUNIT_ASSERT(!xListener->reset());
+}
+
 CPPUNIT_TEST_FIXTURE(MiscTest, testNoThumbnail)
 {
     // Load a document.

Reply via email to