1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 
10 #include <sal/config.h>
11 
12 #include <cppunit/TestFixture.h>
13 #include <cppunit/extensions/HelperMacros.h>
14 #include <cppunit/plugin/TestPlugIn.h>
15 
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>
28 
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.
35 
36 namespace
37 {
38 class Test : public CppUnit::TestFixture
39 {
40 public:
testEnum()41     void testEnum()
42     {
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);
71     }
72 
testStruct()73     void testStruct()
74     {
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);
127     }
128 
testPolyStruct()129     void testPolyStruct()
130     {
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,
137                                         members, param);
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);
180     }
181 
testInterface()182     void testInterface()
183     {
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:
222         CPPUNIT_ASSERT(
223             css::uno::TypeDescription(&basetypes[0]->aBase).equals(&t->ppBaseTypes[0]->aBase));
224         typelib_typedescription_release(td);
225         typelib_typedescriptionreference_release(ref);
226     }
227 
testMultiInterface()228     void testMultiInterface()
229     {
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:
271         CPPUNIT_ASSERT(
272             css::uno::TypeDescription(&basetypes[0]->aBase).equals(&t->ppBaseTypes[0]->aBase));
273         CPPUNIT_ASSERT(
274             css::uno::TypeDescription(&basetypes[1]->aBase).equals(&t->ppBaseTypes[1]->aBase));
275         typelib_typedescription_release(td);
276         typelib_typedescriptionreference_release(ref);
277     }
278 
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();
286 };
287 
288 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
289 }
290 
291 CPPUNIT_PLUGIN_IMPLEMENT();
292 
293 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
294