/* -*- 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 #include #include #include #include #include using namespace css; using namespace css::uno; namespace apitest { XPropertySet::PropsToTest::PropsToTest() : initialized(false) { } namespace { class MockedPropertyChangeListener : public ::cppu::WeakImplHelper { public: MockedPropertyChangeListener() : m_bListenerCalled(false) { } bool m_bListenerCalled; virtual void SAL_CALL propertyChange(const beans::PropertyChangeEvent& /* xEvent */) override { m_bListenerCalled = true; } virtual void SAL_CALL disposing(const lang::EventObject& /* xEventObj */) override {} }; class MockedVetoableChangeListener : public ::cppu::WeakImplHelper { public: MockedVetoableChangeListener() : m_bListenerCalled(false) { } bool m_bListenerCalled; virtual void SAL_CALL vetoableChange(const beans::PropertyChangeEvent& /* xEvent */) override { m_bListenerCalled = true; } virtual void SAL_CALL disposing(const lang::EventObject& /* xEventObj */) override {} }; } void XPropertySet::testPropertyChangeListener() { uno::Reference xPropSet(init(), uno::UNO_QUERY_THROW); uno::Reference xPropInfo = xPropSet->getPropertySetInfo(); fillPropsToTest(xPropInfo); for (const auto& aName : maPropsToTest.bound) { rtl::Reference xListener = new MockedPropertyChangeListener(); xPropSet->addPropertyChangeListener( aName, uno::Reference(xListener)); if (!isPropertyValueChangeable(aName)) continue; CPPUNIT_ASSERT(xListener->m_bListenerCalled); xListener->m_bListenerCalled = false; xPropSet->removePropertyChangeListener( aName, uno::Reference(xListener)); isPropertyValueChangeable(aName); CPPUNIT_ASSERT(!xListener->m_bListenerCalled); } } void XPropertySet::testVetoableChangeListener() { uno::Reference xPropSet(init(), uno::UNO_QUERY_THROW); uno::Reference xPropInfo = xPropSet->getPropertySetInfo(); fillPropsToTest(xPropInfo); for (const auto& aName : maPropsToTest.bound) { rtl::Reference xListener = new MockedVetoableChangeListener(); xPropSet->addVetoableChangeListener( aName, uno::Reference(xListener)); if (!isPropertyValueChangeable(aName)) continue; CPPUNIT_ASSERT(xListener->m_bListenerCalled); xListener->m_bListenerCalled = false; xPropSet->removeVetoableChangeListener( aName, uno::Reference(xListener)); isPropertyValueChangeable(aName); CPPUNIT_ASSERT(!xListener->m_bListenerCalled); } } void XPropertySet::testGetPropertySetInfo() { uno::Reference xPropSet(init(), UNO_QUERY_THROW); uno::Reference xPropInfo = xPropSet->getPropertySetInfo(); if (xPropInfo.is()) { fillPropsToTest(xPropInfo); } else { // TODO: Add a means for the client code to populate the PropsToTest. } } void XPropertySet::testSetPropertyValue() { testGetPropertySetInfo(); for (size_t i = 0, n = maPropsToTest.normal.size(); i < n; ++i) { bool bSuccess = isPropertyValueChangeable(maPropsToTest.normal[i]); CPPUNIT_ASSERT(bSuccess); } } void XPropertySet::testGetPropertyValue() { testGetPropertySetInfo(); uno::Reference xPropSet(init(), UNO_QUERY_THROW); // Check read-only properties. for (size_t i = 0, n = maPropsToTest.readonly.size(); i < n; ++i) { bool bSuccess = getSinglePropertyValue(xPropSet, maPropsToTest.readonly[i]); CPPUNIT_ASSERT(bSuccess); } // Check writable properties. for (size_t i = 0, n = maPropsToTest.normal.size(); i < n; ++i) { bool bSuccess = getSinglePropertyValue(xPropSet, maPropsToTest.normal[i]); CPPUNIT_ASSERT(bSuccess); } } bool XPropertySet::isPropertyValueChangeable(const OUString& rName) { bool bIgnore = isPropertyIgnored(rName); if (bIgnore) return false; uno::Reference xPropSet(init(), UNO_QUERY_THROW); try { uno::Any any = xPropSet->getPropertyValue(rName); const uno::Type& type = any.getValueType(); if (type == cppu::UnoType::get()) { // boolean type bool bOld = any.get(); xPropSet->setPropertyValue(rName, Any(!bOld)); } else if (type == cppu::UnoType::get()) { // 8-bit integer sal_Int8 nOld = any.get(); sal_Int8 nNew = nOld + 1; xPropSet->setPropertyValue(rName, Any(nNew)); } else if (type == cppu::UnoType::get()) { // 16-bit integer sal_Int16 nOld = any.get(); sal_Int16 nNew = nOld + 1; xPropSet->setPropertyValue(rName, Any(nNew)); } else if (type == cppu::UnoType::get()) { // 32-bit integer sal_Int32 nOld = any.get(); sal_Int32 nNew = nOld + 3; xPropSet->setPropertyValue(rName, Any(nNew)); } else if (type == cppu::UnoType::get()) { // 64-bit integer sal_Int64 nOld = any.get(); sal_Int64 nNew = nOld + 4; xPropSet->setPropertyValue(rName, Any(nNew)); } else if (type == cppu::UnoType::get()) { // single precision float fOld = any.get(); float fNew = fOld + 1.2; xPropSet->setPropertyValue(rName, Any(fNew)); } else if (type == cppu::UnoType::get()) { // double precision double fOld = any.get(); double fNew = fOld + 1.3; xPropSet->setPropertyValue(rName, Any(fNew)); } else if (type == cppu::UnoType::get()) { // string type OUString aOld = any.get(); OUString aNew = aOld + "foo"; xPropSet->setPropertyValue(rName, Any(aNew)); } else if (type == cppu::UnoType::get()) { // date time type util::DateTime aDT = any.get(); aDT.Year += 1; xPropSet->setPropertyValue(rName, Any(aDT)); } else if (type == cppu::UnoType>::get()) { auto xComplexColor = any.get>(); auto aComplexColor = model::color::getFromXComplexColor(xComplexColor); xPropSet->setPropertyValue(rName, Any(model::color::createXComplexColor(aComplexColor))); } else { std::cout << "Unknown type:\n" "Type: " << type.getTypeName() << "\n" "Name: " << rName << "\n"; CPPUNIT_ASSERT_MESSAGE( "XPropertySet::isPropertyValueChangeable: unknown type in Any tested.", false); } uno::Any anyTest = xPropSet->getPropertyValue(rName); return any != anyTest; } catch (const uno::Exception&) { std::cout << "Exception thrown while retrieving with property: " << rName << "\n"; CPPUNIT_ASSERT_MESSAGE("XPropertySet::isPropertyValueChangeable: exception thrown while " "retrieving the property value.", false); } return false; } void XPropertySet::fillPropsToTest(const uno::Reference& xPropInfo) { if (maPropsToTest.initialized) return; const uno::Sequence aProps = xPropInfo->getProperties(); // some properties should not be changed in a unspecific way. // TODO: Maybe we should mark these properties read-only, instead of // giving them a special treatment here? std::set aSkip; aSkip.insert(u"PrinterName"_ustr); aSkip.insert(u"CharRelief"_ustr); aSkip.insert(u"IsLayerMode"_ustr); for (const beans::Property& aProp : aProps) { if (aSkip.count(aProp.Name) > 0) continue; if ((aProp.Attributes & beans::PropertyAttribute::READONLY) != 0) { maPropsToTest.readonly.push_back(aProp.Name); continue; } if ((aProp.Attributes & beans::PropertyAttribute::MAYBEVOID) != 0) continue; bool bBound = (aProp.Attributes & beans::PropertyAttribute::BOUND) != 0; bool bConstrained = (aProp.Attributes & beans::PropertyAttribute::CONSTRAINED) != 0; bool bCanChange = isPropertyValueChangeable(aProp.Name); if (bBound && bCanChange) maPropsToTest.bound.push_back(aProp.Name); if (bConstrained && bCanChange) maPropsToTest.constrained.push_back(aProp.Name); if (bCanChange) maPropsToTest.normal.push_back(aProp.Name); } maPropsToTest.initialized = true; } bool XPropertySet::getSinglePropertyValue(const uno::Reference& xPropSet, const OUString& rName) { try { xPropSet->getPropertyValue(rName); return true; } catch (const uno::Exception&) { } return false; } bool XPropertySet::isPropertyIgnored(const OUString& rName) { return m_IgnoreValue.count(rName) > 0; } } // namespace apitest /* vim:set shiftwidth=4 softtabstop=4 expandtab: */