1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <test/bootstrapfixture.hxx>
12 #include <vcl/wrkwin.hxx>
13 #include <vcl/toolkit/edit.hxx>
14 #include <vcl/toolkit/button.hxx>
15 #include <vcl/toolkit/combobox.hxx>
16 #include <vcl/toolkit/dialog.hxx>
17 #include <vcl/toolkit/field.hxx>
18 #include <vcl/virdev.hxx>
19 #include <vcl/tabctrl.hxx>
20 #include <vcl/layout.hxx>
21 #include <vcl/scheduler.hxx>
22 #include <com/sun/star/awt/XWindow.hpp>
23 #include <com/sun/star/awt/XVclWindowPeer.hpp>
24 #include <com/sun/star/lang/XComponent.hpp>
26 class LifecycleTest
: public test::BootstrapFixture
28 void testWidgets(vcl::Window
*pParent
);
31 LifecycleTest() : BootstrapFixture(true, false) {}
34 void testVirtualDevice();
35 void testMultiDispose();
36 void testIsolatedWidgets();
37 void testParentedWidgets();
38 void testChildDispose();
39 void testPostDispose();
43 CPPUNIT_TEST_SUITE(LifecycleTest
);
44 CPPUNIT_TEST(testCast
);
45 CPPUNIT_TEST(testVirtualDevice
);
46 CPPUNIT_TEST(testMultiDispose
);
47 CPPUNIT_TEST(testIsolatedWidgets
);
48 CPPUNIT_TEST(testParentedWidgets
);
49 CPPUNIT_TEST(testChildDispose
);
50 CPPUNIT_TEST(testPostDispose
);
51 CPPUNIT_TEST(testLeakage
);
52 CPPUNIT_TEST(testToolkit
);
53 CPPUNIT_TEST_SUITE_END();
56 // A compile time sanity check
57 void LifecycleTest::testCast()
59 ScopedVclPtrInstance
< PushButton
> xButton( nullptr, 0 );
60 ScopedVclPtr
<vcl::Window
> xWindow(xButton
);
62 ScopedVclPtrInstance
< MetricField
> xField( nullptr, 0 );
63 ScopedVclPtr
<SpinField
> xSpin(xField
);
64 ScopedVclPtr
<Edit
> xEdit(xField
);
66 // the following line should NOT compile
67 // VclPtr<PushButton> xButton2(xWindow);
70 void LifecycleTest::testVirtualDevice()
72 VclPtr
<VirtualDevice
> pVDev
= VclPtr
< VirtualDevice
>::Create();
73 ScopedVclPtrInstance
< VirtualDevice
> pVDev2
;
74 VclPtrInstance
<VirtualDevice
> pVDev3
;
75 VclPtrInstance
<VirtualDevice
> pVDev4(DeviceFormat::WITHOUT_ALPHA
);
76 CPPUNIT_ASSERT(!!pVDev
);
77 CPPUNIT_ASSERT(!!pVDev2
);
78 CPPUNIT_ASSERT(!!pVDev3
);
79 CPPUNIT_ASSERT(!!pVDev4
);
80 pVDev
.disposeAndClear();
81 pVDev4
.disposeAndClear();
84 void LifecycleTest::testMultiDispose()
86 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
91 CPPUNIT_ASSERT(!xWin
->GetWindow(GetWindowType::Parent
));
92 CPPUNIT_ASSERT(!xWin
->GetChild(0));
93 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(0), xWin
->GetChildCount());
96 void LifecycleTest::testWidgets(vcl::Window
*pParent
)
99 ScopedVclPtrInstance
< PushButton
> aPtr( pParent
);
100 (void)aPtr
; // silence unused variable warning
103 ScopedVclPtrInstance
< OKButton
> aPtr( pParent
);
104 (void)aPtr
; // silence unused variable warning
107 ScopedVclPtrInstance
< CancelButton
> aPtr( pParent
);
108 (void)aPtr
; // silence unused variable warning
111 ScopedVclPtrInstance
< HelpButton
> aPtr( pParent
);
112 (void)aPtr
; // silence unused variable warning
115 // Some widgets really insist on adoption.
119 ScopedVclPtrInstance
< CheckBox
> aPtr( pParent
);
120 (void)aPtr
; // silence unused variable warning
123 ScopedVclPtrInstance
< Edit
> aPtr( pParent
);
124 (void)aPtr
; // silence unused variable warning
127 ScopedVclPtrInstance
< ComboBox
> aPtr( pParent
);
128 (void)aPtr
; // silence unused variable warning
131 ScopedVclPtrInstance
< RadioButton
> aPtr( pParent
, true, 0 );
132 (void)aPtr
; // silence unused variable warning
137 void LifecycleTest::testIsolatedWidgets()
139 testWidgets(nullptr);
142 void LifecycleTest::testParentedWidgets()
144 ScopedVclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
145 CPPUNIT_ASSERT(xWin
);
152 class DisposableChild
: public vcl::Window
155 explicit DisposableChild(vcl::Window
*pParent
) : vcl::Window(pParent
) {}
156 virtual ~DisposableChild() override
164 void LifecycleTest::testChildDispose()
166 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
167 CPPUNIT_ASSERT(xWin
);
168 VclPtrInstance
< DisposableChild
> xChild( xWin
.get() );
170 xChild
->disposeOnce();
174 void LifecycleTest::testPostDispose()
176 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
179 // check selected methods continue to work post-dispose
180 CPPUNIT_ASSERT(!xWin
->GetParent());
182 CPPUNIT_ASSERT(!xWin
->IsReallyShown());
183 CPPUNIT_ASSERT(!xWin
->IsEnabled());
184 CPPUNIT_ASSERT(!xWin
->IsInputEnabled());
185 CPPUNIT_ASSERT(!xWin
->GetChild(0));
186 CPPUNIT_ASSERT(!xWin
->GetWindow(GetWindowType::Parent
));
191 template <class vcl_type
>
192 class LeakTestClass
: public vcl_type
196 template<typename
... Arg
>
197 LeakTestClass(bool &bDeleted
, Arg
&&... arg
) :
198 vcl_type(std::forward
<Arg
>(arg
)...),
212 VclPtr
<vcl::Window
> mxRef
;
220 template<typename vcl_type
, typename
... Arg
> static LeakTestObject
*
221 Create(Arg
&&... arg
)
223 LeakTestObject
*pNew
= new LeakTestObject();
224 pNew
->mxRef
= VclPtr
< LeakTestClass
< vcl_type
> >::Create( pNew
->mbDeleted
,
225 std::forward
<Arg
>(arg
)...);
226 pNew
->mpRef
= static_cast<void *>(static_cast<vcl::Window
*>(pNew
->mxRef
));
229 const VclPtr
<vcl::Window
>& getRef() const { return mxRef
; }
230 void disposeAndClear()
232 mxRef
.disposeAndClear();
238 OUStringBuffer aMsg
= "Type '";
239 vcl::Window
*pWin
= static_cast<vcl::Window
*>(mpRef
);
240 aMsg
.appendAscii(typeid(*pWin
).name());
241 aMsg
.append("' not freed after dispose");
242 CPPUNIT_FAIL(OUStringToOString(aMsg
.makeStringAndClear(),
243 RTL_TEXTENCODING_UTF8
).getStr());
250 void LifecycleTest::testLeakage()
252 std::vector
<LeakTestObject
*> aObjects
;
255 aObjects
.push_back(LeakTestObject::Create
<WorkWindow
>(nullptr, WB_APP
|WB_STDWORK
));
256 VclPtr
<vcl::Window
> xParent
= aObjects
.back()->getRef();
258 aObjects
.push_back(LeakTestObject::Create
<PushButton
>(xParent
));
259 aObjects
.push_back(LeakTestObject::Create
<CheckBox
>(xParent
));
260 aObjects
.push_back(LeakTestObject::Create
<Edit
>(xParent
));
261 aObjects
.push_back(LeakTestObject::Create
<ComboBox
>(xParent
));
262 aObjects
.push_back(LeakTestObject::Create
<RadioButton
>(xParent
, true, 0));
264 { // something that looks like a dialog
265 aObjects
.push_back(LeakTestObject::Create
<Dialog
>(xParent
,WB_CLIPCHILDREN
|WB_MOVEABLE
|WB_3DLOOK
|WB_CLOSEABLE
|WB_SIZEABLE
));
266 VclPtr
<vcl::Window
> xDlgParent
= aObjects
.back()->getRef();
267 aObjects
.push_back(LeakTestObject::Create
<VclVBox
>(xDlgParent
));
268 VclPtr
<vcl::Window
> xVBox
= aObjects
.back()->getRef();
269 aObjects
.push_back(LeakTestObject::Create
<VclVButtonBox
>(xVBox
));
272 aObjects
.push_back(LeakTestObject::Create
<Dialog
>(xParent
, u
"PrintProgressDialog"_ustr
, "vcl/ui/printprogressdialog.ui"));
275 for (auto i
= aObjects
.rbegin(); i
!= aObjects
.rend(); ++i
)
276 (*i
)->getRef()->Show();
278 for (auto i
= aObjects
.rbegin(); i
!= aObjects
.rend(); ++i
)
279 (*i
)->disposeAndClear();
281 for (auto i
= aObjects
.begin(); i
!= aObjects
.end(); ++i
)
282 (*i
)->assertDeleted();
284 for (auto i
= aObjects
.begin(); i
!= aObjects
.end(); ++i
)
288 void LifecycleTest::testToolkit()
290 LeakTestObject
*pVclWin
= LeakTestObject::Create
<WorkWindow
>(nullptr, WB_APP
|WB_STDWORK
);
291 css::uno::Reference
<css::awt::XWindow
> xWindow(pVclWin
->getRef()->GetComponentInterface(), css::uno::UNO_QUERY
);
292 CPPUNIT_ASSERT(xWindow
.is());
295 css::uno::Reference
<css::lang::XComponent
> xWinComponent
= xWindow
;
296 CPPUNIT_ASSERT(xWinComponent
.is());
297 CPPUNIT_ASSERT(!pVclWin
->getRef()->isDisposed());
298 xWinComponent
->dispose();
299 CPPUNIT_ASSERT(pVclWin
->getRef()->isDisposed());
302 xWinComponent
.clear();
304 pVclWin
->disposeAndClear();
305 pVclWin
->assertDeleted();
310 CPPUNIT_TEST_SUITE_REGISTRATION(LifecycleTest
);
312 CPPUNIT_PLUGIN_IMPLEMENT();
314 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */