1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <testshl/simpleheader.hxx>
29 
30 #include "com/sun/star/lang/XEventListener.hpp"
31 #include "cppuhelper/interfacecontainer.hxx"
32 #include "cppuhelper/queryinterface.hxx"
33 #include "cppuhelper/implbase1.hxx"
34 #include "cppuhelper/propshlp.hxx"
35 
36 using namespace com::sun::star;
37 using namespace com::sun::star::uno;
38 using namespace com::sun::star::lang;
39 
40 
41 struct equalStr
42 {
43     bool operator()(
44         const char * const &rA,
45         const char * const &rB) const
46         { return !strcmp(rA, rB); }
47 };
48 struct hashStr
49 {
50     size_t operator()( const char * &rName ) const
51     {
52         return rtl::OString(rName).hashCode();
53     }
54 };
55 
56 class ContainerListener;
57 
58 struct ContainerStats {
59     int m_nAlive;
60     int m_nDisposed;
61     ContainerStats() : m_nAlive(0), m_nDisposed(0) {}
62 };
63 
64 class ContainerListener : public ::cppu::WeakImplHelper1< XEventListener >
65 {
66     ContainerStats *m_pStats;
67 public:
68     ContainerListener(ContainerStats *pStats)
69         : m_pStats(pStats) { m_pStats->m_nAlive++; }
70     virtual ~ContainerListener() { m_pStats->m_nAlive--; }
71     virtual void SAL_CALL disposing( const EventObject& )
72         throw (RuntimeException)
73     {
74         m_pStats->m_nDisposed++;
75     }
76 };
77 
78 namespace cppu_ifcontainer
79 {
80     class IfTest : public CppUnit::TestFixture
81     {
82         osl::Mutex m_aGuard;
83         static const int nTests = 10;
84     public:
85         void testCreateDispose()
86         {
87             ContainerStats aStats;
88             cppu::OInterfaceContainerHelper *pContainer;
89 
90             pContainer = new cppu::OInterfaceContainerHelper(m_aGuard);
91 
92             CPPUNIT_ASSERT_MESSAGE("Empty container not empty",
93                                    pContainer->getLength() == 0);
94 
95             int i;
96             for (i = 0; i < nTests; i++)
97             {
98                 Reference<XEventListener> xRef = new ContainerListener(&aStats);
99                 int nNewLen = pContainer->addInterface(xRef);
100 
101                 CPPUNIT_ASSERT_MESSAGE("addition length mismatch",
102                                        nNewLen == i + 1);
103                 CPPUNIT_ASSERT_MESSAGE("addition length mismatch",
104                                        pContainer->getLength() == i + 1);
105             }
106             CPPUNIT_ASSERT_MESSAGE("alive count mismatch",
107                                    aStats.m_nAlive == nTests);
108 
109             EventObject aObj;
110             pContainer->disposeAndClear(aObj);
111 
112             CPPUNIT_ASSERT_MESSAGE("dispose count mismatch",
113                                    aStats.m_nDisposed == nTests);
114             CPPUNIT_ASSERT_MESSAGE("leaked container left alive",
115                                    aStats.m_nAlive == 0);
116 
117             delete pContainer;
118         }
119 
120         void testEnumerate()
121         {
122             int i;
123             ContainerStats aStats;
124             cppu::OInterfaceContainerHelper *pContainer;
125             pContainer = new cppu::OInterfaceContainerHelper(m_aGuard);
126 
127             std::vector< Reference< XEventListener > > aListeners;
128             for (i = 0; i < nTests; i++)
129             {
130                 Reference<XEventListener> xRef = new ContainerListener(&aStats);
131                 int nNewLen = pContainer->addInterface(xRef);
132                 aListeners.push_back(xRef);
133             }
134             Sequence< Reference< XInterface > > aElements;
135             aElements = pContainer->getElements();
136 
137             CPPUNIT_ASSERT_MESSAGE("query contents",
138                                    (int)aElements.getLength() == nTests);
139             if ((int)aElements.getLength() == nTests)
140             {
141                 for (i = 0; i < nTests; i++)
142                 {
143                     CPPUNIT_ASSERT_MESSAGE("mismatching elements",
144                                            aElements[i] == aListeners[i]);
145                 }
146             }
147             pContainer->clear();
148 
149             CPPUNIT_ASSERT_MESSAGE("non-empty container post clear",
150                                    pContainer->getLength() == 0);
151             delete pContainer;
152         }
153 
154         template < typename ContainerType, typename ContainedType >
155         void doContainerTest(const ContainedType *pTypes)
156         {
157             ContainerStats aStats;
158             ContainerType *pContainer;
159             pContainer = new ContainerType(m_aGuard);
160 
161             int i;
162             Reference<XEventListener> xRefs[nTests * 2];
163 
164             // add these interfaces
165             for (i = 0; i < nTests * 2; i++)
166             {
167                 xRefs[i] = new ContainerListener(&aStats);
168                 pContainer->addInterface(pTypes[i / 2], xRefs[i]);
169             }
170 
171             // check it is all there
172             for (i = 0; i < nTests; i++)
173             {
174                 cppu::OInterfaceContainerHelper *pHelper;
175 
176                 pHelper = pContainer->getContainer(pTypes[i]);
177 
178                 CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != NULL);
179                 Sequence<Reference< XInterface > > aSeq = pHelper->getElements();
180                 CPPUNIT_ASSERT_MESSAGE("wrong num elements", aSeq.getLength() == 2);
181                 CPPUNIT_ASSERT_MESSAGE("match", aSeq[0] == xRefs[i*2]);
182                 CPPUNIT_ASSERT_MESSAGE("match", aSeq[1] == xRefs[i*2+1]);
183             }
184 
185             // remove every other interface
186             for (i = 0; i < nTests; i++)
187                 pContainer->removeInterface(pTypes[i], xRefs[i*2+1]);
188 
189             // check it is half there
190             for (i = 0; i < nTests; i++)
191             {
192                 cppu::OInterfaceContainerHelper *pHelper;
193 
194                 pHelper = pContainer->getContainer(pTypes[i]);
195 
196                 CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != NULL);
197                 Sequence<Reference< XInterface > > aSeq = pHelper->getElements();
198                 CPPUNIT_ASSERT_MESSAGE("wrong num elements", aSeq.getLength() == 1);
199                 CPPUNIT_ASSERT_MESSAGE("match", aSeq[0] == xRefs[i*2]);
200             }
201 
202             // remove the 1st half of the rest
203             for (i = 0; i < nTests / 2; i++)
204                 pContainer->removeInterface(pTypes[i], xRefs[i*2]);
205 
206             // check it is half there
207             for (i = 0; i < nTests / 2; i++)
208             {
209                 cppu::OInterfaceContainerHelper *pHelper;
210 
211                 pHelper = pContainer->getContainer(pTypes[i]);
212                 CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != NULL);
213                 Sequence<Reference< XInterface > > aSeq = pHelper->getElements();
214                 CPPUNIT_ASSERT_MESSAGE("wrong num elements", aSeq.getLength() == 0);
215             }
216 
217             delete pContainer;
218         }
219 
220         void testOMultiTypeInterfaceContainerHelper()
221         {
222             uno::Type pTypes[nTests] =
223             {
224                 ::cppu::UnoType< bool >::get(),
225                 ::cppu::UnoType< float >::get(),
226                 ::cppu::UnoType< double >::get(),
227                 ::cppu::UnoType< ::sal_uInt64 >::get(),
228                 ::cppu::UnoType< ::sal_Int64 >::get(),
229                 ::cppu::UnoType< ::sal_uInt32 >::get(),
230                 ::cppu::UnoType< ::sal_Int32 >::get(),
231                 ::cppu::UnoType< ::sal_Int16 >::get(),
232                 ::cppu::UnoType< ::rtl::OUString >::get(),
233                 ::cppu::UnoType< ::sal_Int8 >::get()
234             };
235             doContainerTest< cppu::OMultiTypeInterfaceContainerHelper,
236                 uno::Type> (pTypes);
237         }
238 
239         void testOMultiTypeInterfaceContainerHelperInt32()
240         {
241             sal_Int32 pTypes[nTests] =
242             {
243                 0,
244                 -1,
245                 1,
246                 256,
247                 1024,
248                 3,
249                 7,
250                 8,
251                 9,
252                 10
253             };
254             doContainerTest< cppu::OMultiTypeInterfaceContainerHelperInt32, sal_Int32> (pTypes);
255         }
256 
257         void testOMultiTypeInterfaceContainerHelperVar()
258         {
259             typedef ::cppu::OMultiTypeInterfaceContainerHelperVar<
260                 const char *,hashStr,equalStr> StrContainer;
261 
262             const char *pTypes[nTests] =
263             {
264                 "this_is", "such", "fun", "writing", "unit", "tests", "when", "it", "works", "anyway"
265             };
266             doContainerTest< StrContainer, const char *> (pTypes);
267         }
268 
269         // Automatic registration code
270         CPPUNIT_TEST_SUITE(IfTest);
271         CPPUNIT_TEST(testCreateDispose);
272         CPPUNIT_TEST(testEnumerate);
273         CPPUNIT_TEST(testOMultiTypeInterfaceContainerHelper);
274         CPPUNIT_TEST(testOMultiTypeInterfaceContainerHelperVar);
275         CPPUNIT_TEST(testOMultiTypeInterfaceContainerHelperInt32);
276         CPPUNIT_TEST_SUITE_END();
277     };
278 } // namespace cppu_ifcontainer
279 
280 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(cppu_ifcontainer::IfTest,
281                                       "cppu_ifcontainer");
282 
283 NOADDITIONAL;
284