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/types.h>
21 
22 #include <cppunit/TestFixture.h>
23 #include <cppunit/plugin/TestPlugIn.h>
24 #include <cppunit/extensions/HelperMacros.h>
25 
26 #include <Interface1.hpp>
27 
28 namespace
29 {
30 
31 using ::com::sun::star::uno::Type;
32 using ::com::sun::star::uno::Any;
33 using ::com::sun::star::uno::Reference;
34 using ::com::sun::star::uno::RuntimeException;
35 using ::com::sun::star::uno::UNO_SET_THROW;
36 
37 class Foo: public Interface1
38 {
39 public:
Foo()40     Foo()
41         :m_refCount(0)
42     {
43     }
44 
45     Foo(const Foo&) = delete;
46     const Foo& operator=(const Foo&) = delete;
47 
queryInterface(const Type & _type)48     virtual Any SAL_CALL queryInterface(const Type & _type) override
49     {
50         if (_type == cppu::UnoType<XInterface>::get())
51         {
52             return css::uno::makeAny<css::uno::Reference<css::uno::XInterface>>(
53                 this);
54         }
55         if (_type == cppu::UnoType<Interface1>::get())
56         {
57             return css::uno::makeAny<css::uno::Reference<Interface1>>(this);
58         }
59 
60         return Any();
61     }
62 
acquire()63     virtual void SAL_CALL acquire() noexcept override
64     {
65         osl_atomic_increment( &m_refCount );
66     }
67 
release()68     virtual void SAL_CALL release() noexcept override
69     {
70         if ( 0 == osl_atomic_decrement( &m_refCount ) )
71             delete this;
72     }
73 
74 protected:
~Foo()75     virtual ~Foo()
76     {
77     }
78 
79 private:
80     oslInterlockedCount m_refCount;
81 };
82 
83 // Check that the up-casting Reference conversion constructor catches the
84 // intended cases:
85 
86 struct Base1: public css::uno::XInterface {
87     virtual ~Base1() = delete;
static_type__anon0f4b5f440111::Base188     static ::css::uno::Type const & static_type(void * = nullptr) // loplugin:refcounting
89     { return ::cppu::UnoType<Base1>::get(); }
90 };
91 struct Base2: public Base1 {
92     virtual ~Base2() override = delete;
93 };
94 struct Base3: public Base1 { virtual ~Base3() override = delete; };
95 struct Derived: public Base2, public Base3 {
96     virtual ~Derived() override = delete;
97 };
98 
99 // The special case using the conversion operator instead:
testUpcast1(css::uno::Reference<Derived> const & ref)100 css::uno::Reference< css::uno::XInterface > testUpcast1(
101     css::uno::Reference< Derived > const & ref)
102 {
103     Base1::static_type(); // prevent loplugin:unreffun firing
104     return ref;
105 }
106 
107 // The normal up-cast case:
testUpcast2(css::uno::Reference<Base2> const & ref)108 css::uno::Reference< Base1 > testUpcast2(
109     css::uno::Reference< Base2 > const & ref)
110 { return ref; }
111 
112 // Commenting this in should cause a compiler error due to an ambiguous up-cast:
113 /*
114 css::uno::Reference< Base1 > testFailingUpcast3(
115     css::uno::Reference< Derived > const & ref)
116 { return ref; }
117 */
118 
119 // Commenting this in should cause a compiler error due to a down-cast:
120 /*
121 css::uno::Reference< Base2 > testFailingUpcast4(
122     css::uno::Reference< Base1 > const & ref)
123 { return ref; }
124 */
125 
126 // Commenting this in should cause a compiler error due to a down-cast:
127 /*
128 css::uno::Reference< Base1 > testFailingUpcast5(
129     css::uno::Reference< css::uno::XInterface > const & ref)
130 { return ref; }
131 */
132 
133 class Test: public ::CppUnit::TestFixture
134 {
135 
136 public:
137     void testUnoSetThrow();
138     void testUpcastCompilation();
139 
140     CPPUNIT_TEST_SUITE(Test);
141     CPPUNIT_TEST(testUnoSetThrow);
142     CPPUNIT_TEST(testUpcastCompilation);
143     CPPUNIT_TEST_SUITE_END();
144 };
145 
testUnoSetThrow()146 void Test::testUnoSetThrow()
147 {
148     Reference< Interface1 > xNull;
149     Reference< Interface1 > xFoo( new Foo );
150 
151     // ctor taking Reference< interface_type >
152     bool bCaughtException = false;
153     try { Reference< Interface1 > x( xNull, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
154     CPPUNIT_ASSERT_EQUAL( true, bCaughtException );
155 
156     bCaughtException = false;
157     try { Reference< Interface1 > x( xFoo, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
158     CPPUNIT_ASSERT_EQUAL( false, bCaughtException );
159 
160     // ctor taking interface_type*
161     bCaughtException = false;
162     try { Reference< Interface1 > x( xNull.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
163     CPPUNIT_ASSERT_EQUAL( true, bCaughtException );
164 
165     bCaughtException = false;
166     try { Reference< Interface1 > x( xFoo.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
167     CPPUNIT_ASSERT_EQUAL( false, bCaughtException );
168 
169     Reference< Interface1 > x;
170     // "set" taking Reference< interface_type >
171     bCaughtException = false;
172     try { x.set( xNull, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
173     CPPUNIT_ASSERT_EQUAL( true, bCaughtException );
174 
175     bCaughtException = false;
176     try { x.set( xFoo, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
177     CPPUNIT_ASSERT_EQUAL( false, bCaughtException );
178 
179     // "set" taking interface_type*
180     bCaughtException = false;
181     try { x.set( xNull.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
182     CPPUNIT_ASSERT_EQUAL( true, bCaughtException );
183 
184     bCaughtException = false;
185     try { x.set( xFoo.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; }
186     CPPUNIT_ASSERT_EQUAL( false, bCaughtException );
187 }
188 
189 // Include a dummy test calling those functions, to avoid warnings about those
190 // functions being unused:
testUpcastCompilation()191 void Test::testUpcastCompilation()
192 {
193     testUpcast1(css::uno::Reference< Derived >());
194     testUpcast2(css::uno::Reference< Base2 >());
195 }
196 
197 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
198 
199 }   // namespace
200 
201 CPPUNIT_PLUGIN_IMPLEMENT();
202 
203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
204