Line data Source code
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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <cstddef>
23 :
24 : #include <com/sun/star/beans/NamedValue.hpp>
25 : #include <com/sun/star/beans/PropertyChangeEvent.hpp>
26 : #include <com/sun/star/beans/XPropertyChangeListener.hpp>
27 : #include <com/sun/star/beans/XPropertySet.hpp>
28 : #include <com/sun/star/beans/XPropertyState.hpp>
29 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
30 : #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
31 : #include <com/sun/star/container/XNameReplace.hpp>
32 : #include <com/sun/star/container/XNamed.hpp>
33 : #include <com/sun/star/lang/EventObject.hpp>
34 : #include <com/sun/star/lang/XComponent.hpp>
35 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 : #include <com/sun/star/uno/Any.hxx>
37 : #include <com/sun/star/uno/Reference.hxx>
38 : #include <com/sun/star/uno/RuntimeException.hpp>
39 : #include <com/sun/star/uno/Sequence.hxx>
40 : #include <com/sun/star/uno/XComponentContext.hpp>
41 : #include <com/sun/star/uno/XInterface.hpp>
42 : #include <com/sun/star/util/XChangesBatch.hpp>
43 : #include <cppuhelper/implbase1.hxx>
44 : #include <osl/conditn.hxx>
45 : #include <osl/thread.h>
46 : #include <osl/thread.hxx>
47 : #include <osl/time.h>
48 : #include <rtl/ref.hxx>
49 : #include <rtl/string.h>
50 : #include <rtl/textcvt.h>
51 : #include <rtl/ustrbuf.hxx>
52 : #include <rtl/ustring.h>
53 : #include <rtl/ustring.hxx>
54 : #include <sal/types.h>
55 : #include <comphelper/processfactory.hxx>
56 : #include <unotest/bootstrapfixturebase.hxx>
57 :
58 : namespace {
59 :
60 21 : class Test: public CppUnit::TestFixture {
61 : public:
62 : virtual void setUp() SAL_OVERRIDE;
63 : virtual void tearDown() SAL_OVERRIDE;
64 :
65 : void testKeyFetch();
66 : void testKeySet();
67 : void testKeyReset();
68 : void testSetSetMemberName();
69 : void testReadCommands();
70 : #if 0
71 : void testThreads();
72 : #endif
73 : void testRecursive();
74 : void testCrossThreads();
75 :
76 : css::uno::Any getKey(
77 : OUString const & path, OUString const & relative) const;
78 :
79 : void setKey(
80 : OUString const & path, OUString const & name,
81 : css::uno::Any const & value) const;
82 :
83 : bool resetKey(OUString const & path, OUString const & name) const;
84 :
85 : css::uno::Reference< css::uno::XInterface > createViewAccess(
86 : OUString const & path) const;
87 :
88 : css::uno::Reference< css::uno::XInterface > createUpdateAccess(
89 : OUString const & path) const;
90 :
91 2 : CPPUNIT_TEST_SUITE(Test);
92 1 : CPPUNIT_TEST(testKeyFetch);
93 1 : CPPUNIT_TEST(testKeySet);
94 1 : CPPUNIT_TEST(testKeyReset);
95 1 : CPPUNIT_TEST(testSetSetMemberName);
96 1 : CPPUNIT_TEST(testReadCommands);
97 : #if 0
98 : CPPUNIT_TEST(testThreads);
99 : #endif
100 1 : CPPUNIT_TEST(testRecursive);
101 1 : CPPUNIT_TEST(testCrossThreads);
102 5 : CPPUNIT_TEST_SUITE_END();
103 :
104 : private:
105 : css::uno::Reference< css::uno::XComponentContext > context_;
106 : css::uno::Reference< css::lang::XMultiServiceFactory > provider_;
107 : };
108 :
109 : class RecursiveTest:
110 : public cppu::WeakImplHelper1< css::beans::XPropertyChangeListener >
111 : {
112 : public:
113 : RecursiveTest(Test const & theTest, int count, bool * destroyed);
114 :
115 : void test();
116 :
117 : protected:
118 : virtual ~RecursiveTest();
119 :
120 : virtual void step() const = 0;
121 :
122 : Test const & test_;
123 :
124 : private:
125 : virtual void SAL_CALL disposing(css::lang::EventObject const &)
126 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
127 :
128 : virtual void SAL_CALL propertyChange(
129 : css::beans::PropertyChangeEvent const &)
130 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
131 :
132 : int count_;
133 : bool * destroyed_;
134 : css::uno::Reference< css::beans::XPropertySet > properties_;
135 : };
136 :
137 2 : RecursiveTest::RecursiveTest(
138 : Test const & theTest, int count, bool * destroyed):
139 2 : test_(theTest), count_(count), destroyed_(destroyed)
140 2 : {}
141 :
142 2 : void RecursiveTest::test()
143 : {
144 4 : properties_ = css::uno::Reference< css::beans::XPropertySet >(
145 : test_.createUpdateAccess(
146 : OUString("/org.openoffice.Office.UI.GenericCommands/UserInterface/Commands/"
147 : ".uno:WebHtml")),
148 2 : css::uno::UNO_QUERY_THROW);
149 2 : properties_->addPropertyChangeListener(
150 2 : OUString("Label"), this);
151 2 : step();
152 2 : CPPUNIT_ASSERT(count_ == 0);
153 : css::uno::Reference< css::lang::XComponent >(
154 2 : properties_, css::uno::UNO_QUERY_THROW)->dispose();
155 2 : }
156 :
157 4 : RecursiveTest::~RecursiveTest()
158 : {
159 2 : *destroyed_ = true;
160 2 : }
161 :
162 2 : void RecursiveTest::disposing(css::lang::EventObject const & Source)
163 : throw (css::uno::RuntimeException, std::exception)
164 : {
165 2 : CPPUNIT_ASSERT(properties_.is() && Source.Source == properties_);
166 2 : properties_.clear();
167 2 : }
168 :
169 112 : void RecursiveTest::propertyChange(css::beans::PropertyChangeEvent const & evt)
170 : throw (css::uno::RuntimeException, std::exception)
171 : {
172 112 : CPPUNIT_ASSERT( evt.Source == properties_ && evt.PropertyName == "Label" );
173 112 : if (count_ > 0) {
174 110 : --count_;
175 110 : step();
176 : }
177 112 : }
178 :
179 4 : class SimpleRecursiveTest: public RecursiveTest {
180 : public:
181 : SimpleRecursiveTest(Test const & theTest, int count, bool * destroyed);
182 :
183 : private:
184 : virtual void step() const SAL_OVERRIDE;
185 : };
186 :
187 2 : SimpleRecursiveTest::SimpleRecursiveTest(
188 : Test const & theTest, int count, bool * destroyed):
189 2 : RecursiveTest(theTest, count, destroyed)
190 2 : {}
191 :
192 112 : void SimpleRecursiveTest::step() const
193 : {
194 : test_.setKey(
195 : OUString("/org.openoffice.Office.UI.GenericCommands/UserInterface/Commands/"
196 : ".uno:WebHtml"),
197 : OUString("Label"),
198 112 : css::uno::makeAny(OUString("step")));
199 112 : }
200 :
201 7 : void Test::setUp()
202 : {
203 14 : provider_ = css::configuration::theDefaultProvider::get(
204 7 : comphelper::getProcessComponentContext() );
205 7 : }
206 :
207 7 : void Test::tearDown()
208 : {
209 7 : }
210 :
211 1 : void Test::testKeyFetch()
212 : {
213 1 : OUString s;
214 2 : CPPUNIT_ASSERT(
215 : getKey(
216 : OUString("/org.openoffice.System"),
217 : OUString("L10N/Locale")) >>=
218 2 : s);
219 1 : }
220 :
221 1 : void Test::testKeySet()
222 : {
223 : setKey(
224 : OUString("/org.openoffice.System/L10N"),
225 : OUString("Locale"),
226 1 : css::uno::makeAny(OUString("com.sun.star.configuration.backend.LocaleBackend UILocale")));
227 1 : OUString s;
228 2 : CPPUNIT_ASSERT(
229 : getKey(
230 : OUString("/org.openoffice.System/L10N"),
231 : OUString("Locale")) >>=
232 1 : s);
233 1 : CPPUNIT_ASSERT( s == "com.sun.star.configuration.backend.LocaleBackend UILocale" );
234 1 : }
235 :
236 1 : void Test::testKeyReset()
237 : {
238 2 : if (resetKey(
239 : OUString("/org.openoffice.System/L10N"),
240 2 : OUString("Locale")))
241 : {
242 0 : OUString s;
243 0 : CPPUNIT_ASSERT(
244 : getKey(
245 : OUString("/org.openoffice.System/L10N"),
246 : OUString("Locale")) >>=
247 0 : s);
248 0 : CPPUNIT_ASSERT( s == "com.sun.star.configuration.backend.LocaleBackend Locale" );
249 : }
250 1 : }
251 :
252 1 : void Test::testSetSetMemberName()
253 : {
254 1 : OUString s;
255 2 : CPPUNIT_ASSERT(
256 : getKey(
257 : OUString("/org.openoffice.Office.UI.GenericCommands/UserInterface/Commands/"
258 : ".uno:FontworkShapeType"),
259 : OUString("Label")) >>=
260 1 : s);
261 1 : CPPUNIT_ASSERT( s == "Fontwork Shape" );
262 :
263 : css::uno::Reference< css::container::XNameAccess > access(
264 : createUpdateAccess(
265 : OUString("/org.openoffice.Office.UI.GenericCommands/UserInterface/"
266 : "Commands")),
267 2 : css::uno::UNO_QUERY_THROW);
268 2 : css::uno::Reference< css::container::XNamed > member;
269 1 : access->getByName(
270 2 : OUString(".uno:FontworkGalleryFloater")) >>=
271 1 : member;
272 1 : CPPUNIT_ASSERT(member.is());
273 1 : member->setName(
274 1 : OUString(".uno:FontworkShapeType"));
275 : css::uno::Reference< css::util::XChangesBatch >(
276 1 : access, css::uno::UNO_QUERY_THROW)->commitChanges();
277 : css::uno::Reference< css::lang::XComponent >(
278 1 : access, css::uno::UNO_QUERY_THROW)->dispose();
279 :
280 2 : CPPUNIT_ASSERT(
281 : getKey(
282 : OUString("/org.openoffice.Office.UI.GenericCommands/UserInterface/Commands/"
283 : ".uno:FontworkShapeType"),
284 : OUString("Label")) >>=
285 1 : s);
286 2 : CPPUNIT_ASSERT( s == "Fontwork Gallery..." );
287 1 : }
288 :
289 1 : void Test::testReadCommands()
290 : {
291 : css::uno::Reference< css::container::XNameAccess > access(
292 : createViewAccess(
293 : OUString("/org.openoffice.Office.UI.GenericCommands/UserInterface/"
294 : "Commands")),
295 1 : css::uno::UNO_QUERY_THROW);
296 2 : css::uno::Sequence< OUString > names(access->getElementNames());
297 :
298 : /*CPPUNIT_ASSERT_EQUAL(749, names.getLength());*/
299 : // testSetSetMemberName() already removed ".uno:FontworkGalleryFloater"
300 1 : sal_uInt32 n = osl_getGlobalTimer();
301 9 : for (int i = 0; i < 8; ++i) {
302 6104 : for (sal_Int32 j = 0; j < names.getLength(); ++j) {
303 6096 : css::uno::Reference< css::container::XNameAccess > child;
304 6096 : if (access->getByName(names[j]) >>= child) {
305 6096 : CPPUNIT_ASSERT(child.is());
306 6096 : child->getByName(
307 6096 : OUString("Label"));
308 6096 : child->getByName(
309 6096 : OUString("ContextLabel"));
310 6096 : child->getByName(
311 6096 : OUString("Properties"));
312 : }
313 6096 : }
314 : }
315 1 : n = osl_getGlobalTimer() - n;
316 1 : printf("Reading elements took %" SAL_PRIuUINT32 " ms\n", n);
317 : css::uno::Reference< css::lang::XComponent >(
318 2 : access, css::uno::UNO_QUERY_THROW)->dispose();
319 1 : }
320 :
321 1 : void Test::testRecursive()
322 : {
323 1 : bool destroyed = false;
324 : rtl::Reference< RecursiveTest >(
325 1 : new SimpleRecursiveTest(*this, 100, &destroyed))->test();
326 1 : CPPUNIT_ASSERT(destroyed);
327 1 : }
328 :
329 1 : void Test::testCrossThreads()
330 : {
331 1 : bool destroyed = false;
332 : rtl::Reference< RecursiveTest >(
333 1 : new SimpleRecursiveTest(*this, 10, &destroyed))->test();
334 1 : CPPUNIT_ASSERT(destroyed);
335 1 : }
336 :
337 4 : css::uno::Any Test::getKey(
338 : OUString const & path, OUString const & relative) const
339 : {
340 : css::uno::Reference< css::container::XHierarchicalNameAccess > access(
341 4 : createViewAccess(path), css::uno::UNO_QUERY_THROW);
342 4 : css::uno::Any value(access->getByHierarchicalName(relative));
343 : css::uno::Reference< css::lang::XComponent >(
344 4 : access, css::uno::UNO_QUERY_THROW)->dispose();
345 4 : return value;
346 : }
347 :
348 113 : void Test::setKey(
349 : OUString const & path, OUString const & name,
350 : css::uno::Any const & value) const
351 : {
352 : css::uno::Reference< css::container::XNameReplace > access(
353 113 : createUpdateAccess(path), css::uno::UNO_QUERY_THROW);
354 113 : access->replaceByName(name, value);
355 : css::uno::Reference< css::util::XChangesBatch >(
356 113 : access, css::uno::UNO_QUERY_THROW)->commitChanges();
357 : css::uno::Reference< css::lang::XComponent >(
358 113 : access, css::uno::UNO_QUERY_THROW)->dispose();
359 113 : }
360 :
361 1 : bool Test::resetKey(OUString const & path, OUString const & name)
362 : const
363 : {
364 : //TODO: support setPropertyToDefault
365 : css::uno::Reference< css::util::XChangesBatch > access(
366 1 : createUpdateAccess(path), css::uno::UNO_QUERY_THROW);
367 : css::uno::Reference< css::beans::XPropertyState > state(
368 2 : access, css::uno::UNO_QUERY);
369 1 : if (!state.is()) {
370 1 : return false;
371 : }
372 0 : state->setPropertyToDefault(name);
373 0 : access->commitChanges();
374 : css::uno::Reference< css::lang::XComponent >(
375 0 : access, css::uno::UNO_QUERY_THROW)->dispose();
376 1 : return true;
377 : }
378 :
379 5 : css::uno::Reference< css::uno::XInterface > Test::createViewAccess(
380 : OUString const & path) const
381 : {
382 : css::uno::Any arg(
383 : css::uno::makeAny(
384 : css::beans::NamedValue(
385 : OUString("nodepath"),
386 5 : css::uno::makeAny(path))));
387 5 : return provider_->createInstanceWithArguments(
388 : OUString(
389 : "com.sun.star.configuration.ConfigurationAccess"),
390 5 : css::uno::Sequence< css::uno::Any >(&arg, 1));
391 : }
392 :
393 117 : css::uno::Reference< css::uno::XInterface > Test::createUpdateAccess(
394 : OUString const & path) const
395 : {
396 : css::uno::Any arg(
397 : css::uno::makeAny(
398 : css::beans::NamedValue(
399 : OUString("nodepath"),
400 117 : css::uno::makeAny(path))));
401 117 : return provider_->createInstanceWithArguments(
402 : OUString(
403 : "com.sun.star.configuration.ConfigurationUpdateAccess"),
404 117 : css::uno::Sequence< css::uno::Any >(&arg, 1));
405 : }
406 :
407 : #if 0
408 : class TestThread: public osl::Thread {
409 : public:
410 : TestThread(osl::Condition & stop);
411 :
412 : bool getSuccess() const;
413 :
414 : protected:
415 : virtual bool iteration() = 0;
416 :
417 : private:
418 : virtual void SAL_CALL run() SAL_OVERRIDE;
419 :
420 : osl::Condition & stop_;
421 : bool success_;
422 : };
423 :
424 : TestThread::TestThread(
425 : osl::Condition & stop):
426 : stop_(stop), success_(true)
427 : {}
428 :
429 : bool TestThread::getSuccess() const
430 : {
431 : return success_;
432 : }
433 :
434 : void TestThread::run()
435 : {
436 : try {
437 : while (!stop_.check()) {
438 : if (!iteration()) {
439 : success_ = false;
440 : }
441 : }
442 : } catch (...) {
443 : success_ = false;
444 : }
445 : }
446 :
447 : class ReaderThread: public TestThread {
448 : public:
449 : ReaderThread(
450 : osl::Condition & stop, Test const & test, OUString const & path,
451 : OUString const & relative);
452 :
453 : private:
454 : virtual bool iteration() SAL_OVERRIDE;
455 :
456 : Test const & test_;
457 : OUString path_;
458 : OUString relative_;
459 : };
460 :
461 : ReaderThread::ReaderThread(
462 : osl::Condition & stop, Test const & test, OUString const & path,
463 : OUString const & relative):
464 : TestThread(stop), test_(test), path_(path), relative_(relative)
465 : {
466 : create();
467 : }
468 :
469 : bool ReaderThread::iteration()
470 : {
471 : return test_.getKey(path_, relative_).hasValue();
472 : }
473 :
474 : void normalize(
475 : OUString const & path, OUString const & relative,
476 : OUString * normalizedPath, OUString * name)
477 : {
478 : sal_Int32 i = relative.lastIndexOf('/');
479 : if (i == -1) {
480 : *normalizedPath = path;
481 : *name = relative;
482 : } else {
483 : OUStringBuffer buf(path);
484 : buf.append('/');
485 : buf.append(relative.copy(0, i));
486 : *normalizedPath = buf.makeStringAndClear();
487 : *name = relative.copy(i + 1);
488 : }
489 : }
490 :
491 : class WriterThread: public TestThread {
492 : public:
493 : WriterThread(
494 : osl::Condition & stop, Test const & test, OUString const & path,
495 : OUString const & relative);
496 :
497 : private:
498 : virtual bool iteration() SAL_OVERRIDE;
499 :
500 : Test const & test_;
501 : OUString path_;
502 : OUString name_;
503 : std::size_t index_;
504 : };
505 :
506 : WriterThread::WriterThread(
507 : osl::Condition & stop, Test const & test, OUString const & path,
508 : OUString const & relative):
509 : TestThread(stop), test_(test), index_(0)
510 : {
511 : normalize(path, relative, &path_, &name_);
512 : create();
513 : }
514 :
515 : bool WriterThread::iteration() {
516 : OUString options[] = {
517 : OUString("fish"),
518 : OUString("chips"),
519 : OUString("kippers"),
520 : OUString("bloaters") };
521 :
522 : test_.setKey(path_, name_, css::uno::makeAny(options[index_]));
523 : index_ = (index_ + 1) % (sizeof options / sizeof (OUString));
524 : return true;
525 : }
526 :
527 : void Test::testThreads()
528 : {
529 : struct Entry { OUString path; OUString relative; };
530 : Entry list[] = {
531 : { OUString(
532 : "/org.openoffice.Office.UI.GenericCommands"),
533 : OUString(
534 : "UserInterface/Commands/.uno:WebHtml") },
535 : { OUString(
536 : "/org.openoffice.Office.UI.GenericCommands"),
537 : OUString(
538 : "UserInterface/Commands/.uno:NewPresentation") },
539 : { OUString(
540 : "/org.openoffice.Office.UI.GenericCommands"),
541 : OUString(
542 : "UserInterface/Commands/.uno:RecentFileList") },
543 : { OUString("/org.openoffice.System"),
544 : OUString("L10N/Locale") }
545 : };
546 : std::size_t const numReaders = sizeof list / sizeof (Entry);
547 : std::size_t const numWriters = numReaders - 2;
548 : ReaderThread * readers[numReaders];
549 : WriterThread * writers[numWriters];
550 : osl::Condition stop;
551 : for (std::size_t i = 0; i < numReaders; ++i) {
552 : CPPUNIT_ASSERT(getKey(list[i].path, list[i].relative).hasValue());
553 : readers[i] = new ReaderThread(
554 : stop, *this, list[i].path, list[i].relative);
555 : }
556 : for (std::size_t i = 0; i < numWriters; ++i) {
557 : writers[i] = new WriterThread(
558 : stop, *this, list[i].path, list[i].relative);
559 : }
560 : for (int i = 0; i < 5; ++i) {
561 : for (std::size_t j = 0; j < numReaders; ++j) {
562 : OUString path;
563 : OUString name;
564 : normalize(list[j].path, list[j].relative, &path, &name);
565 : resetKey(path, name);
566 : osl::Thread::yield();
567 : }
568 : }
569 : stop.set();
570 : bool success = true;
571 : for (std::size_t i = 0; i < numReaders; ++i) {
572 : readers[i]->join();
573 : CPPUNIT_ASSERT(readers[i]->getSuccess());
574 : delete readers[i];
575 : }
576 : for (std::size_t i = 0; i < numWriters; ++i) {
577 : writers[i]->join();
578 : CPPUNIT_ASSERT(writers[i]->getSuccess());
579 : delete writers[i];
580 : }
581 :
582 : CPPUNIT_ASSERT(success);
583 : }
584 : #endif
585 :
586 1 : CPPUNIT_TEST_SUITE_REGISTRATION(Test);
587 :
588 : }
589 :
590 4 : CPPUNIT_PLUGIN_IMPLEMENT();
591 :
592 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|