LibreOffice Module test (master)  1
xpropertyset.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
11 
12 #include <com/sun/star/beans/Property.hpp>
13 #include <com/sun/star/beans/PropertyAttribute.hpp>
14 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
15 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
16 #include <com/sun/star/beans/XPropertySet.hpp>
17 #include <com/sun/star/beans/XVetoableChangeListener.hpp>
18 #include <com/sun/star/lang/EventObject.hpp>
19 #include <com/sun/star/util/DateTime.hpp>
20 
21 #include <com/sun/star/uno/Any.hxx>
22 #include <com/sun/star/uno/Reference.hxx>
23 #include <com/sun/star/uno/Type.h>
24 
25 #include <cppuhelper/implbase.hxx>
26 #include <rtl/ref.hxx>
27 
28 #include <cppunit/TestAssert.h>
29 
30 using namespace css;
31 using namespace css::uno;
32 
33 namespace apitest
34 {
35 XPropertySet::PropsToTest::PropsToTest()
36  : initialized(false)
37 {
38 }
39 
40 namespace
41 {
42 class MockedPropertyChangeListener : public ::cppu::WeakImplHelper<beans::XPropertyChangeListener>
43 {
44 public:
45  MockedPropertyChangeListener()
46  : m_bListenerCalled(false)
47  {
48  }
49 
51 
52  virtual void SAL_CALL propertyChange(const beans::PropertyChangeEvent& /* xEvent */) override
53  {
54  m_bListenerCalled = true;
55  }
56 
57  virtual void SAL_CALL disposing(const lang::EventObject& /* xEventObj */) override {}
58 };
59 
60 class MockedVetoableChangeListener : public ::cppu::WeakImplHelper<beans::XVetoableChangeListener>
61 {
62 public:
63  MockedVetoableChangeListener()
64  : m_bListenerCalled(false)
65  {
66  }
67 
68  bool m_bListenerCalled;
69 
70  virtual void SAL_CALL vetoableChange(const beans::PropertyChangeEvent& /* xEvent */) override
71  {
72  m_bListenerCalled = true;
73  }
74 
75  virtual void SAL_CALL disposing(const lang::EventObject& /* xEventObj */) override {}
76 };
77 }
78 
80 {
81  uno::Reference<beans::XPropertySet> xPropSet(init(), uno::UNO_QUERY_THROW);
82  uno::Reference<beans::XPropertySetInfo> xPropInfo = xPropSet->getPropertySetInfo();
83  fillPropsToTest(xPropInfo);
84 
85  for (const auto& aName : maPropsToTest.bound)
86  {
87  rtl::Reference<MockedPropertyChangeListener> xListener = new MockedPropertyChangeListener();
88  xPropSet->addPropertyChangeListener(
89  aName, uno::Reference<beans::XPropertyChangeListener>(xListener.get()));
91  continue;
92 
93  CPPUNIT_ASSERT(xListener->m_bListenerCalled);
94 
95  xListener->m_bListenerCalled = false;
96  xPropSet->removePropertyChangeListener(
97  aName, uno::Reference<beans::XPropertyChangeListener>(xListener.get()));
99  CPPUNIT_ASSERT(!xListener->m_bListenerCalled);
100  }
101 }
102 
104 {
105  uno::Reference<beans::XPropertySet> xPropSet(init(), uno::UNO_QUERY_THROW);
106  uno::Reference<beans::XPropertySetInfo> xPropInfo = xPropSet->getPropertySetInfo();
107  fillPropsToTest(xPropInfo);
108 
109  for (const auto& aName : maPropsToTest.bound)
110  {
111  rtl::Reference<MockedVetoableChangeListener> xListener = new MockedVetoableChangeListener();
112  xPropSet->addVetoableChangeListener(
113  aName, uno::Reference<beans::XVetoableChangeListener>(xListener.get()));
115  continue;
116 
117  CPPUNIT_ASSERT(xListener->m_bListenerCalled);
118 
119  xListener->m_bListenerCalled = false;
120  xPropSet->removeVetoableChangeListener(
121  aName, uno::Reference<beans::XVetoableChangeListener>(xListener.get()));
123  CPPUNIT_ASSERT(!xListener->m_bListenerCalled);
124  }
125 }
126 
128 {
129  uno::Reference<beans::XPropertySet> xPropSet(init(), UNO_QUERY_THROW);
130  uno::Reference<beans::XPropertySetInfo> xPropInfo = xPropSet->getPropertySetInfo();
131  if (xPropInfo.is())
132  {
133  fillPropsToTest(xPropInfo);
134  }
135  else
136  {
137  // TODO: Add a means for the client code to populate the PropsToTest.
138  }
139 }
140 
142 {
144 
145  for (size_t i = 0, n = maPropsToTest.normal.size(); i < n; ++i)
146  {
148  CPPUNIT_ASSERT(bSuccess);
149  }
150 }
151 
153 {
155  uno::Reference<beans::XPropertySet> xPropSet(init(), UNO_QUERY_THROW);
156 
157  // Check read-only properties.
158  for (size_t i = 0, n = maPropsToTest.readonly.size(); i < n; ++i)
159  {
160  bool bSuccess = getSinglePropertyValue(xPropSet, maPropsToTest.readonly[i]);
161  CPPUNIT_ASSERT(bSuccess);
162  }
163 
164  // Check writable properties.
165  for (size_t i = 0, n = maPropsToTest.normal.size(); i < n; ++i)
166  {
167  bool bSuccess = getSinglePropertyValue(xPropSet, maPropsToTest.normal[i]);
168  CPPUNIT_ASSERT(bSuccess);
169  }
170 }
171 
172 bool XPropertySet::isPropertyValueChangeable(const OUString& rName)
173 {
174  bool bIgnore = isPropertyIgnored(rName);
175  if (bIgnore)
176  return false;
177 
178  uno::Reference<beans::XPropertySet> xPropSet(init(), UNO_QUERY_THROW);
179  try
180  {
181  uno::Any any = xPropSet->getPropertyValue(rName);
182  const uno::Type& type = any.getValueType();
183  if (type == cppu::UnoType<bool>::get())
184  {
185  // boolean type
186  bool bOld = any.get<bool>();
187  xPropSet->setPropertyValue(rName, makeAny(!bOld));
188  }
189  else if (type == cppu::UnoType<sal_Int8>::get())
190  {
191  // 8-bit integer
192  sal_Int8 nOld = any.get<sal_Int8>();
193  sal_Int8 nNew = nOld + 1;
194  xPropSet->setPropertyValue(rName, makeAny(nNew));
195  }
196  else if (type == cppu::UnoType<sal_Int16>::get())
197  {
198  // 16-bit integer
199  sal_Int16 nOld = any.get<sal_Int16>();
200  sal_Int16 nNew = nOld + 1;
201  xPropSet->setPropertyValue(rName, makeAny(nNew));
202  }
203  else if (type == cppu::UnoType<sal_Int32>::get())
204  {
205  // 32-bit integer
206  sal_Int32 nOld = any.get<sal_Int32>();
207  sal_Int32 nNew = nOld + 3;
208  xPropSet->setPropertyValue(rName, makeAny(nNew));
209  }
210  else if (type == cppu::UnoType<sal_Int64>::get())
211  {
212  // 64-bit integer
213  sal_Int64 nOld = any.get<sal_Int64>();
214  sal_Int64 nNew = nOld + 4;
215  xPropSet->setPropertyValue(rName, makeAny(nNew));
216  }
217  else if (type == cppu::UnoType<float>::get())
218  {
219  // single precision
220  float fOld = any.get<float>();
221  float fNew = fOld + 1.2;
222  xPropSet->setPropertyValue(rName, makeAny(fNew));
223  }
224  else if (type == cppu::UnoType<double>::get())
225  {
226  // double precision
227  double fOld = any.get<double>();
228  double fNew = fOld + 1.3;
229  xPropSet->setPropertyValue(rName, makeAny(fNew));
230  }
231  else if (type == cppu::UnoType<OUString>::get())
232  {
233  // string type
234  OUString aOld = any.get<OUString>();
235  OUString aNew = aOld + "foo";
236  xPropSet->setPropertyValue(rName, makeAny(aNew));
237  }
238  else if (type == cppu::UnoType<util::DateTime>::get())
239  {
240  // date time type
241  util::DateTime aDT = any.get<util::DateTime>();
242  aDT.Year += 1;
243  xPropSet->setPropertyValue(rName, makeAny(aDT));
244  }
245  else
246  {
247  std::cout << "Unknown type:\n"
248  "Type: "
249  << type.getTypeName()
250  << "\n"
251  "Name: "
252  << rName << "\n";
253  CPPUNIT_ASSERT_MESSAGE(
254  "XPropertySet::isPropertyValueChangeable: unknown type in Any tested.", false);
255  }
256 
257  uno::Any anyTest = xPropSet->getPropertyValue(rName);
258  return any != anyTest;
259  }
260  catch (const uno::Exception&)
261  {
262  std::cout << "Exception thrown while retrieving with property: " << rName << "\n";
263  CPPUNIT_ASSERT_MESSAGE("XPropertySet::isPropertyValueChangeable: exception thrown while "
264  "retrieving the property value.",
265  false);
266  }
267 
268  return false;
269 }
270 
271 void XPropertySet::fillPropsToTest(const uno::Reference<beans::XPropertySetInfo>& xPropInfo)
272 {
274  return;
275 
276  const uno::Sequence<beans::Property> aProps = xPropInfo->getProperties();
277 
278  // some properties should not be changed in a unspecific way.
279  // TODO: Maybe we should mark these properties read-only, instead of
280  // giving them a special treatment here?
281  std::set<OUString> aSkip;
282  aSkip.insert("PrinterName");
283  aSkip.insert("CharRelief");
284  aSkip.insert("IsLayerMode");
285 
286  for (const beans::Property& aProp : aProps)
287  {
288  if (aSkip.count(aProp.Name) > 0)
289  continue;
290 
291  if ((aProp.Attributes & beans::PropertyAttribute::READONLY) != 0)
292  {
293  maPropsToTest.readonly.push_back(aProp.Name);
294  continue;
295  }
296 
297  if ((aProp.Attributes & beans::PropertyAttribute::MAYBEVOID) != 0)
298  continue;
299 
300  bool bBound = (aProp.Attributes & beans::PropertyAttribute::BOUND) != 0;
301  bool bConstrained = (aProp.Attributes & beans::PropertyAttribute::CONSTRAINED) != 0;
302  bool bCanChange = isPropertyValueChangeable(aProp.Name);
303 
304  if (bBound && bCanChange)
305  maPropsToTest.bound.push_back(aProp.Name);
306 
307  if (bConstrained && bCanChange)
308  maPropsToTest.constrained.push_back(aProp.Name);
309 
310  if (bCanChange)
311  maPropsToTest.normal.push_back(aProp.Name);
312  }
313 
314  maPropsToTest.initialized = true;
315 }
316 
317 bool XPropertySet::getSinglePropertyValue(const uno::Reference<beans::XPropertySet>& xPropSet,
318  const OUString& rName)
319 {
320  try
321  {
322  xPropSet->getPropertyValue(rName);
323  return true;
324  }
325  catch (const uno::Exception&)
326  {
327  }
328  return false;
329 }
330 
331 bool XPropertySet::isPropertyIgnored(const OUString& rName)
332 {
333  return m_IgnoreValue.count(rName) > 0;
334 }
335 
336 } // namespace apitest
337 
338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual bool isPropertyIgnored(const OUString &rName)
signed char sal_Int8
sal_Int64 n
std::vector< OUString > readonly
static bool getSinglePropertyValue(const css::uno::Reference< css::beans::XPropertySet > &xPropSet, const OUString &rName)
bool isPropertyValueChangeable(const OUString &rName)
std::vector< OUString > bound
bool m_bListenerCalled
PropsToTest maPropsToTest
virtual css::uno::Reference< css::uno::XInterface > init()=0
int i
const Any & any
std::vector< OUString > normal
void fillPropsToTest(const css::uno::Reference< css::beans::XPropertySetInfo > &xPropInfo)
OUString aName
std::vector< OUString > constrained
std::set< OUString > m_IgnoreValue
ResultType type
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)