1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <sal/config.h>
12 #include <cppunit/TestFixture.h>
13 #include <cppunit/extensions/HelperMacros.h>
14 #include <cppunit/plugin/TestPlugIn.h>
16 #include <com/sun/star/io/XActiveDataSink.hpp>
17 #include <com/sun/star/io/XTextInputStream.hpp>
18 #include <com/sun/star/lang/EventObject.hpp>
19 #include <com/sun/star/script/FinishReason.hpp>
20 #include <com/sun/star/uno/Any.hxx>
21 #include <com/sun/star/uno/Type.hxx>
22 #include <com/sun/star/uno/XInterface.hpp>
23 #include <cppu/unotype.hxx>
24 #include <rtl/ustring.hxx>
25 #include <sal/types.h>
26 #include <typelib/typedescription.h>
27 #include <typelib/typedescription.hxx>
29 // Test that typelib_typedescription_register as called from typelib_typedescription_complete
30 // returns a correct typelib_TypeDescription and keeps pointers from the original
31 // typelib_TypeDescription intact (see tdf#115399 "Data race in typelib_typedescription_register").
32 // This code uses sufficiently "obscure" types in typelib_static_*_type_init to make it unlikely
33 // that they are already instantiated and registered with the type description manager, which might
34 // cause inconsistencies.
38 class Test
: public CppUnit::TestFixture
43 typelib_TypeDescriptionReference
* ref
= nullptr;
44 typelib_static_enum_type_init(&ref
, "com.sun.star.script.MemberType", 0);
45 CPPUNIT_ASSERT(ref
!= nullptr);
46 typelib_TypeDescription
* td
= ref
->pType
;
47 CPPUNIT_ASSERT(td
!= nullptr);
48 typelib_typedescription_acquire(td
);
49 CPPUNIT_ASSERT(!td
->bComplete
);
50 auto t
= reinterpret_cast<typelib_EnumTypeDescription
*>(td
);
51 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nDefaultEnumValue
);
52 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nEnumValues
);
53 CPPUNIT_ASSERT(t
->ppEnumNames
== nullptr);
54 CPPUNIT_ASSERT(t
->pEnumValues
== nullptr);
55 CPPUNIT_ASSERT(typelib_typedescription_complete(&td
));
56 CPPUNIT_ASSERT(td
!= nullptr);
57 CPPUNIT_ASSERT(td
->bComplete
);
58 t
= reinterpret_cast<typelib_EnumTypeDescription
*>(td
);
59 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nDefaultEnumValue
);
60 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), t
->nEnumValues
);
61 CPPUNIT_ASSERT(t
->ppEnumNames
!= nullptr);
62 CPPUNIT_ASSERT_EQUAL(OUString("METHOD"), OUString::unacquired(&t
->ppEnumNames
[0]));
63 CPPUNIT_ASSERT_EQUAL(OUString("PROPERTY"), OUString::unacquired(&t
->ppEnumNames
[1]));
64 CPPUNIT_ASSERT_EQUAL(OUString("UNKNOWN"), OUString::unacquired(&t
->ppEnumNames
[2]));
65 CPPUNIT_ASSERT(t
->pEnumValues
!= nullptr);
66 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->pEnumValues
[0]);
67 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), t
->pEnumValues
[1]);
68 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t
->pEnumValues
[2]);
69 typelib_typedescription_release(td
);
70 typelib_typedescriptionreference_release(ref
);
75 auto const t0
= cppu::UnoType
<css::lang::EventObject
>::get();
76 auto const t1
= cppu::UnoType
<css::script::FinishReason
>::get();
77 auto const t2
= cppu::UnoType
<OUString
>::get();
78 auto const t3
= cppu::UnoType
<css::uno::Any
>::get();
79 typelib_TypeDescriptionReference
* ref
= nullptr;
80 typelib_TypeDescriptionReference
* members
[3]
81 = { t1
.getTypeLibType(), t2
.getTypeLibType(), t3
.getTypeLibType() };
82 typelib_static_struct_type_init(&ref
, "com.sun.star.script.FinishEngineEvent",
83 t0
.getTypeLibType(), 3, members
, nullptr);
84 CPPUNIT_ASSERT(ref
!= nullptr);
85 typelib_TypeDescription
* td
= ref
->pType
;
86 CPPUNIT_ASSERT(td
!= nullptr);
87 typelib_typedescription_acquire(td
);
88 CPPUNIT_ASSERT(!td
->bComplete
);
89 auto t
= reinterpret_cast<typelib_StructTypeDescription
*>(td
);
90 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->aBase
.pBaseTypeDescription
->aBase
).equals(t0
));
91 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), t
->aBase
.nMembers
);
92 auto const offsets
= t
->aBase
.pMemberOffsets
;
93 CPPUNIT_ASSERT(offsets
!= nullptr);
94 auto const typerefs
= t
->aBase
.ppTypeRefs
;
95 CPPUNIT_ASSERT(typerefs
!= nullptr);
96 CPPUNIT_ASSERT_EQUAL(t1
, css::uno::Type(typerefs
[0]));
97 CPPUNIT_ASSERT_EQUAL(t2
, css::uno::Type(typerefs
[1]));
98 CPPUNIT_ASSERT_EQUAL(t3
, css::uno::Type(typerefs
[2]));
99 CPPUNIT_ASSERT(t
->aBase
.ppMemberNames
== nullptr);
100 CPPUNIT_ASSERT(t
->pParameterizedTypes
== nullptr);
101 CPPUNIT_ASSERT(typelib_typedescription_complete(&td
));
102 CPPUNIT_ASSERT(td
!= nullptr);
103 CPPUNIT_ASSERT(td
->bComplete
);
104 t
= reinterpret_cast<typelib_StructTypeDescription
*>(td
);
105 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->aBase
.pBaseTypeDescription
->aBase
).equals(t0
));
106 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), t
->aBase
.nMembers
);
107 CPPUNIT_ASSERT(t
->aBase
.pMemberOffsets
!= nullptr);
108 CPPUNIT_ASSERT(t
->aBase
.ppTypeRefs
!= nullptr);
109 CPPUNIT_ASSERT_EQUAL(t1
, css::uno::Type(t
->aBase
.ppTypeRefs
[0]));
110 CPPUNIT_ASSERT_EQUAL(t2
, css::uno::Type(t
->aBase
.ppTypeRefs
[1]));
111 CPPUNIT_ASSERT_EQUAL(t3
, css::uno::Type(t
->aBase
.ppTypeRefs
[2]));
112 CPPUNIT_ASSERT(t
->aBase
.ppMemberNames
!= nullptr);
113 CPPUNIT_ASSERT_EQUAL(OUString("Finish"), OUString::unacquired(&t
->aBase
.ppMemberNames
[0]));
114 CPPUNIT_ASSERT_EQUAL(OUString("ErrorMessage"),
115 OUString::unacquired(&t
->aBase
.ppMemberNames
[1]));
116 CPPUNIT_ASSERT_EQUAL(OUString("Return"), OUString::unacquired(&t
->aBase
.ppMemberNames
[2]));
117 CPPUNIT_ASSERT(t
->pParameterizedTypes
== nullptr);
118 // `offsets` and `typerefs` must still be valid:
119 CPPUNIT_ASSERT_EQUAL(t
->aBase
.pMemberOffsets
[0], offsets
[0]);
120 CPPUNIT_ASSERT_EQUAL(t
->aBase
.pMemberOffsets
[1], offsets
[1]);
121 CPPUNIT_ASSERT_EQUAL(t
->aBase
.pMemberOffsets
[2], offsets
[2]);
122 CPPUNIT_ASSERT_EQUAL(css::uno::Type(t
->aBase
.ppTypeRefs
[0]), css::uno::Type(typerefs
[0]));
123 CPPUNIT_ASSERT_EQUAL(css::uno::Type(t
->aBase
.ppTypeRefs
[1]), css::uno::Type(typerefs
[1]));
124 CPPUNIT_ASSERT_EQUAL(css::uno::Type(t
->aBase
.ppTypeRefs
[2]), css::uno::Type(typerefs
[2]));
125 typelib_typedescription_release(td
);
126 typelib_typedescriptionreference_release(ref
);
129 void testPolyStruct()
131 auto const t1
= cppu::UnoType
<bool>::get();
132 auto const t2
= cppu::UnoType
<sal_Int32
>::get();
133 typelib_TypeDescriptionReference
* ref
= nullptr;
134 typelib_TypeDescriptionReference
* members
[2] = { t1
.getTypeLibType(), t2
.getTypeLibType() };
135 sal_Bool
const param
[2] = { false, true };
136 typelib_static_struct_type_init(&ref
, "com.sun.star.beans.Optional<long>", nullptr, 2,
138 CPPUNIT_ASSERT(ref
!= nullptr);
139 typelib_TypeDescription
* td
= ref
->pType
;
140 CPPUNIT_ASSERT(td
!= nullptr);
141 typelib_typedescription_acquire(td
);
142 CPPUNIT_ASSERT(!td
->bComplete
);
143 auto t
= reinterpret_cast<typelib_StructTypeDescription
*>(td
);
144 CPPUNIT_ASSERT(t
->aBase
.pBaseTypeDescription
== nullptr);
145 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t
->aBase
.nMembers
);
146 auto const offsets
= t
->aBase
.pMemberOffsets
;
147 CPPUNIT_ASSERT(offsets
!= nullptr);
148 auto const typerefs
= t
->aBase
.ppTypeRefs
;
149 CPPUNIT_ASSERT(typerefs
!= nullptr);
150 CPPUNIT_ASSERT_EQUAL(t1
, css::uno::Type(typerefs
[0]));
151 CPPUNIT_ASSERT_EQUAL(t2
, css::uno::Type(typerefs
[1]));
152 CPPUNIT_ASSERT(t
->aBase
.ppMemberNames
== nullptr);
153 CPPUNIT_ASSERT(t
->pParameterizedTypes
!= nullptr);
154 CPPUNIT_ASSERT_EQUAL(param
[0], t
->pParameterizedTypes
[0]);
155 CPPUNIT_ASSERT_EQUAL(param
[1], t
->pParameterizedTypes
[1]);
156 CPPUNIT_ASSERT(typelib_typedescription_complete(&td
));
157 CPPUNIT_ASSERT(td
!= nullptr);
158 CPPUNIT_ASSERT(td
->bComplete
);
159 t
= reinterpret_cast<typelib_StructTypeDescription
*>(td
);
160 CPPUNIT_ASSERT(t
->aBase
.pBaseTypeDescription
== nullptr);
161 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t
->aBase
.nMembers
);
162 CPPUNIT_ASSERT(t
->aBase
.pMemberOffsets
!= nullptr);
163 CPPUNIT_ASSERT(t
->aBase
.ppTypeRefs
!= nullptr);
164 CPPUNIT_ASSERT_EQUAL(t1
, css::uno::Type(t
->aBase
.ppTypeRefs
[0]));
165 CPPUNIT_ASSERT_EQUAL(t2
, css::uno::Type(t
->aBase
.ppTypeRefs
[1]));
166 CPPUNIT_ASSERT(t
->aBase
.ppMemberNames
!= nullptr);
167 CPPUNIT_ASSERT_EQUAL(OUString("IsPresent"),
168 OUString::unacquired(&t
->aBase
.ppMemberNames
[0]));
169 CPPUNIT_ASSERT_EQUAL(OUString("Value"), OUString::unacquired(&t
->aBase
.ppMemberNames
[1]));
170 CPPUNIT_ASSERT(t
->pParameterizedTypes
!= nullptr);
171 CPPUNIT_ASSERT_EQUAL(param
[0], t
->pParameterizedTypes
[0]);
172 CPPUNIT_ASSERT_EQUAL(param
[1], t
->pParameterizedTypes
[1]);
173 // `offsets` and `typerefs` must still be valid:
174 CPPUNIT_ASSERT_EQUAL(t
->aBase
.pMemberOffsets
[0], offsets
[0]);
175 CPPUNIT_ASSERT_EQUAL(t
->aBase
.pMemberOffsets
[1], offsets
[1]);
176 CPPUNIT_ASSERT_EQUAL(css::uno::Type(t
->aBase
.ppTypeRefs
[0]), css::uno::Type(typerefs
[0]));
177 CPPUNIT_ASSERT_EQUAL(css::uno::Type(t
->aBase
.ppTypeRefs
[1]), css::uno::Type(typerefs
[1]));
178 typelib_typedescription_release(td
);
179 typelib_typedescriptionreference_release(ref
);
184 auto const t0
= cppu::UnoType
<css::uno::XInterface
>::get();
185 typelib_TypeDescriptionReference
* ref
= nullptr;
186 typelib_TypeDescriptionReference
* bases
[1] = { t0
.getTypeLibType() };
187 typelib_static_mi_interface_type_init(&ref
, "com.sun.star.script.XTypeConverter", 1, bases
);
188 CPPUNIT_ASSERT(ref
!= nullptr);
189 typelib_TypeDescription
* td
= ref
->pType
;
190 CPPUNIT_ASSERT(td
!= nullptr);
191 typelib_typedescription_acquire(td
);
192 CPPUNIT_ASSERT(!td
->bComplete
);
193 auto t
= reinterpret_cast<typelib_InterfaceTypeDescription
*>(td
);
194 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->pBaseTypeDescription
->aBase
).equals(t0
));
195 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nMembers
);
196 CPPUNIT_ASSERT(t
->ppMembers
== nullptr);
197 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nAllMembers
);
198 CPPUNIT_ASSERT(t
->ppAllMembers
== nullptr);
199 CPPUNIT_ASSERT(t
->pMapMemberIndexToFunctionIndex
== nullptr);
200 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nMapFunctionIndexToMemberIndex
);
201 CPPUNIT_ASSERT(t
->pMapFunctionIndexToMemberIndex
== nullptr);
202 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), t
->nBaseTypes
);
203 auto const basetypes
= t
->ppBaseTypes
;
204 CPPUNIT_ASSERT(basetypes
!= nullptr);
205 CPPUNIT_ASSERT(css::uno::TypeDescription(&basetypes
[0]->aBase
).equals(t0
));
206 CPPUNIT_ASSERT(typelib_typedescription_complete(&td
));
207 CPPUNIT_ASSERT(td
!= nullptr);
208 CPPUNIT_ASSERT(td
->bComplete
);
209 t
= reinterpret_cast<typelib_InterfaceTypeDescription
*>(td
);
210 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->pBaseTypeDescription
->aBase
).equals(t0
));
211 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t
->nMembers
);
212 CPPUNIT_ASSERT(t
->ppMembers
!= nullptr);
213 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), t
->nAllMembers
);
214 CPPUNIT_ASSERT(t
->ppAllMembers
!= nullptr);
215 CPPUNIT_ASSERT(t
->pMapMemberIndexToFunctionIndex
!= nullptr);
216 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), t
->nMapFunctionIndexToMemberIndex
);
217 CPPUNIT_ASSERT(t
->pMapFunctionIndexToMemberIndex
!= nullptr);
218 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), t
->nBaseTypes
);
219 CPPUNIT_ASSERT(t
->ppBaseTypes
!= nullptr);
220 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->ppBaseTypes
[0]->aBase
).equals(t0
));
221 // `basetypes` must still be valid:
223 css::uno::TypeDescription(&basetypes
[0]->aBase
).equals(&t
->ppBaseTypes
[0]->aBase
));
224 typelib_typedescription_release(td
);
225 typelib_typedescriptionreference_release(ref
);
228 void testMultiInterface()
230 auto const t1
= cppu::UnoType
<css::io::XTextInputStream
>::get();
231 auto const t2
= cppu::UnoType
<css::io::XActiveDataSink
>::get();
232 typelib_TypeDescriptionReference
* ref
= nullptr;
233 typelib_TypeDescriptionReference
* bases
[2] = { t1
.getTypeLibType(), t2
.getTypeLibType() };
234 typelib_static_mi_interface_type_init(&ref
, "com.sun.star.io.XTextInputStream2", 2, bases
);
235 CPPUNIT_ASSERT(ref
!= nullptr);
236 typelib_TypeDescription
* td
= ref
->pType
;
237 CPPUNIT_ASSERT(td
!= nullptr);
238 typelib_typedescription_acquire(td
);
239 CPPUNIT_ASSERT(!td
->bComplete
);
240 auto t
= reinterpret_cast<typelib_InterfaceTypeDescription
*>(td
);
241 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->pBaseTypeDescription
->aBase
).equals(t1
));
242 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nMembers
);
243 CPPUNIT_ASSERT(t
->ppMembers
== nullptr);
244 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nAllMembers
);
245 CPPUNIT_ASSERT(t
->ppAllMembers
== nullptr);
246 CPPUNIT_ASSERT(t
->pMapMemberIndexToFunctionIndex
== nullptr);
247 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nMapFunctionIndexToMemberIndex
);
248 CPPUNIT_ASSERT(t
->pMapFunctionIndexToMemberIndex
== nullptr);
249 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t
->nBaseTypes
);
250 auto const basetypes
= t
->ppBaseTypes
;
251 CPPUNIT_ASSERT(basetypes
!= nullptr);
252 CPPUNIT_ASSERT(css::uno::TypeDescription(&basetypes
[0]->aBase
).equals(t1
));
253 CPPUNIT_ASSERT(css::uno::TypeDescription(&basetypes
[1]->aBase
).equals(t2
));
254 CPPUNIT_ASSERT(typelib_typedescription_complete(&td
));
255 CPPUNIT_ASSERT(td
!= nullptr);
256 CPPUNIT_ASSERT(td
->bComplete
);
257 t
= reinterpret_cast<typelib_InterfaceTypeDescription
*>(td
);
258 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->pBaseTypeDescription
->aBase
).equals(t1
));
259 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t
->nMembers
);
260 CPPUNIT_ASSERT(t
->ppMembers
== nullptr);
261 CPPUNIT_ASSERT_EQUAL(sal_Int32(14), t
->nAllMembers
);
262 CPPUNIT_ASSERT(t
->ppAllMembers
!= nullptr);
263 CPPUNIT_ASSERT(t
->pMapMemberIndexToFunctionIndex
!= nullptr);
264 CPPUNIT_ASSERT_EQUAL(sal_Int32(14), t
->nMapFunctionIndexToMemberIndex
);
265 CPPUNIT_ASSERT(t
->pMapFunctionIndexToMemberIndex
!= nullptr);
266 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t
->nBaseTypes
);
267 CPPUNIT_ASSERT(t
->ppBaseTypes
!= nullptr);
268 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->ppBaseTypes
[0]->aBase
).equals(t1
));
269 CPPUNIT_ASSERT(css::uno::TypeDescription(&t
->ppBaseTypes
[1]->aBase
).equals(t2
));
270 // `basetypes` must still be valid:
272 css::uno::TypeDescription(&basetypes
[0]->aBase
).equals(&t
->ppBaseTypes
[0]->aBase
));
274 css::uno::TypeDescription(&basetypes
[1]->aBase
).equals(&t
->ppBaseTypes
[1]->aBase
));
275 typelib_typedescription_release(td
);
276 typelib_typedescriptionreference_release(ref
);
279 CPPUNIT_TEST_SUITE(Test
);
280 CPPUNIT_TEST(testEnum
);
281 CPPUNIT_TEST(testStruct
);
282 CPPUNIT_TEST(testPolyStruct
);
283 CPPUNIT_TEST(testInterface
);
284 CPPUNIT_TEST(testMultiInterface
);
285 CPPUNIT_TEST_SUITE_END();
288 CPPUNIT_TEST_SUITE_REGISTRATION(Test
);
291 CPPUNIT_PLUGIN_IMPLEMENT();
293 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */