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