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/XWindowPeer.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();
44 CPPUNIT_TEST_SUITE(LifecycleTest
);
45 CPPUNIT_TEST(testCast
);
46 CPPUNIT_TEST(testVirtualDevice
);
47 CPPUNIT_TEST(testMultiDispose
);
48 CPPUNIT_TEST(testIsolatedWidgets
);
49 CPPUNIT_TEST(testParentedWidgets
);
50 CPPUNIT_TEST(testChildDispose
);
51 CPPUNIT_TEST(testPostDispose
);
52 CPPUNIT_TEST(testFocus
);
53 CPPUNIT_TEST(testLeakage
);
54 CPPUNIT_TEST(testToolkit
);
55 CPPUNIT_TEST_SUITE_END();
58 // A compile time sanity check
59 void LifecycleTest::testCast()
61 ScopedVclPtrInstance
< PushButton
> xButton( nullptr, 0 );
62 ScopedVclPtr
<vcl::Window
> xWindow(xButton
);
64 ScopedVclPtrInstance
< MetricField
> xField( nullptr, 0 );
65 ScopedVclPtr
<SpinField
> xSpin(xField
);
66 ScopedVclPtr
<Edit
> xEdit(xField
);
68 // the following line should NOT compile
69 // VclPtr<PushButton> xButton2(xWindow);
72 void LifecycleTest::testVirtualDevice()
74 VclPtr
<VirtualDevice
> pVDev
= VclPtr
< VirtualDevice
>::Create();
75 ScopedVclPtrInstance
< VirtualDevice
> pVDev2
;
76 VclPtrInstance
<VirtualDevice
> pVDev3
;
77 VclPtrInstance
<VirtualDevice
> pVDev4(DeviceFormat::BITMASK
);
78 CPPUNIT_ASSERT(!!pVDev
&& !!pVDev2
&& !!pVDev3
&& !!pVDev4
);
79 pVDev
.disposeAndClear();
80 pVDev4
.disposeAndClear();
83 void LifecycleTest::testMultiDispose()
85 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
90 CPPUNIT_ASSERT(!xWin
->GetWindow(GetWindowType::Parent
));
91 CPPUNIT_ASSERT(!xWin
->GetChild(0));
92 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(0), xWin
->GetChildCount());
95 void LifecycleTest::testWidgets(vcl::Window
*pParent
)
98 ScopedVclPtrInstance
< PushButton
> aPtr( pParent
);
99 (void)aPtr
; // silence unused variable warning
102 ScopedVclPtrInstance
< OKButton
> aPtr( pParent
);
103 (void)aPtr
; // silence unused variable warning
106 ScopedVclPtrInstance
< CancelButton
> aPtr( pParent
);
107 (void)aPtr
; // silence unused variable warning
110 ScopedVclPtrInstance
< HelpButton
> aPtr( pParent
);
111 (void)aPtr
; // silence unused variable warning
114 // Some widgets really insist on adoption.
118 ScopedVclPtrInstance
< CheckBox
> aPtr( pParent
);
119 (void)aPtr
; // silence unused variable warning
122 ScopedVclPtrInstance
< Edit
> aPtr( pParent
);
123 (void)aPtr
; // silence unused variable warning
126 ScopedVclPtrInstance
< ComboBox
> aPtr( pParent
);
127 (void)aPtr
; // silence unused variable warning
130 ScopedVclPtrInstance
< RadioButton
> aPtr( pParent
, true, 0 );
131 (void)aPtr
; // silence unused variable warning
136 void LifecycleTest::testIsolatedWidgets()
138 testWidgets(nullptr);
141 void LifecycleTest::testParentedWidgets()
143 ScopedVclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
144 CPPUNIT_ASSERT(xWin
);
151 class DisposableChild
: public vcl::Window
154 explicit DisposableChild(vcl::Window
*pParent
) : vcl::Window(pParent
) {}
155 virtual ~DisposableChild() override
163 void LifecycleTest::testChildDispose()
165 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
166 CPPUNIT_ASSERT(xWin
);
167 VclPtrInstance
< DisposableChild
> xChild( xWin
.get() );
169 xChild
->disposeOnce();
173 void LifecycleTest::testPostDispose()
175 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
178 // check selected methods continue to work post-dispose
179 CPPUNIT_ASSERT(!xWin
->GetParent());
181 CPPUNIT_ASSERT(!xWin
->IsReallyShown());
182 CPPUNIT_ASSERT(!xWin
->IsEnabled());
183 CPPUNIT_ASSERT(!xWin
->IsInputEnabled());
184 CPPUNIT_ASSERT(!xWin
->GetChild(0));
185 CPPUNIT_ASSERT(!xWin
->GetWindow(GetWindowType::Parent
));
190 class FocusCrashPostDispose
: public TabControl
193 explicit FocusCrashPostDispose(vcl::Window
*pParent
) :
194 TabControl(pParent
, 0)
197 virtual bool PreNotify( NotifyEvent
& ) override
201 virtual bool EventNotify( NotifyEvent
& ) override
205 virtual void GetFocus() override
207 CPPUNIT_FAIL("get focus");
209 virtual void LoseFocus() override
211 CPPUNIT_FAIL("this should never be called");
217 void LifecycleTest::testFocus()
219 ScopedVclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
220 ScopedVclPtrInstance
< FocusCrashPostDispose
> xChild(xWin
);
223 // process asynchronous ToTop
224 Scheduler::ProcessTaskScheduling();
225 // FIXME: really awful to test focus issues without showing windows.
226 // CPPUNIT_ASSERT(xChild->HasFocus());
231 template <class vcl_type
>
232 class LeakTestClass
: public vcl_type
236 template<typename
... Arg
>
237 LeakTestClass(bool &bDeleted
, Arg
&&... arg
) :
238 vcl_type(std::forward
<Arg
>(arg
)...),
252 VclPtr
<vcl::Window
> mxRef
;
260 template<typename vcl_type
, typename
... Arg
> static LeakTestObject
*
261 Create(Arg
&&... arg
)
263 LeakTestObject
*pNew
= new LeakTestObject();
264 pNew
->mxRef
= VclPtr
< LeakTestClass
< vcl_type
> >::Create( pNew
->mbDeleted
,
265 std::forward
<Arg
>(arg
)...);
266 pNew
->mpRef
= static_cast<void *>(static_cast<vcl::Window
*>(pNew
->mxRef
));
269 const VclPtr
<vcl::Window
>& getRef() const { return mxRef
; }
270 void disposeAndClear()
272 mxRef
.disposeAndClear();
278 OUStringBuffer aMsg
= "Type '";
279 vcl::Window
*pWin
= static_cast<vcl::Window
*>(mpRef
);
280 aMsg
.appendAscii(typeid(*pWin
).name());
281 aMsg
.append("' not freed after dispose");
282 CPPUNIT_FAIL(OUStringToOString(aMsg
.makeStringAndClear(),
283 RTL_TEXTENCODING_UTF8
).getStr());
290 void LifecycleTest::testLeakage()
292 std::vector
<LeakTestObject
*> aObjects
;
295 aObjects
.push_back(LeakTestObject::Create
<WorkWindow
>(nullptr, WB_APP
|WB_STDWORK
));
296 VclPtr
<vcl::Window
> xParent
= aObjects
.back()->getRef();
298 aObjects
.push_back(LeakTestObject::Create
<PushButton
>(xParent
));
299 aObjects
.push_back(LeakTestObject::Create
<CheckBox
>(xParent
));
300 aObjects
.push_back(LeakTestObject::Create
<Edit
>(xParent
));
301 aObjects
.push_back(LeakTestObject::Create
<ComboBox
>(xParent
));
302 aObjects
.push_back(LeakTestObject::Create
<RadioButton
>(xParent
, true, 0));
304 { // something that looks like a dialog
305 aObjects
.push_back(LeakTestObject::Create
<Dialog
>(xParent
,WB_CLIPCHILDREN
|WB_MOVEABLE
|WB_3DLOOK
|WB_CLOSEABLE
|WB_SIZEABLE
));
306 VclPtr
<vcl::Window
> xDlgParent
= aObjects
.back()->getRef();
307 aObjects
.push_back(LeakTestObject::Create
<VclVBox
>(xDlgParent
));
308 VclPtr
<vcl::Window
> xVBox
= aObjects
.back()->getRef();
309 aObjects
.push_back(LeakTestObject::Create
<VclVButtonBox
>(xVBox
));
312 aObjects
.push_back(LeakTestObject::Create
<Dialog
>(xParent
, "PrintProgressDialog", "vcl/ui/printprogressdialog.ui"));
315 for (auto i
= aObjects
.rbegin(); i
!= aObjects
.rend(); ++i
)
316 (*i
)->getRef()->Show();
318 for (auto i
= aObjects
.rbegin(); i
!= aObjects
.rend(); ++i
)
319 (*i
)->disposeAndClear();
321 for (auto i
= aObjects
.begin(); i
!= aObjects
.end(); ++i
)
322 (*i
)->assertDeleted();
324 for (auto i
= aObjects
.begin(); i
!= aObjects
.end(); ++i
)
328 void LifecycleTest::testToolkit()
330 LeakTestObject
*pVclWin
= LeakTestObject::Create
<WorkWindow
>(nullptr, WB_APP
|WB_STDWORK
);
331 css::uno::Reference
<css::awt::XWindow
> xWindow(pVclWin
->getRef()->GetComponentInterface(), css::uno::UNO_QUERY
);
332 CPPUNIT_ASSERT(xWindow
.is());
335 css::uno::Reference
<css::lang::XComponent
> xWinComponent
= xWindow
;
336 CPPUNIT_ASSERT(xWinComponent
.is());
337 CPPUNIT_ASSERT(!pVclWin
->getRef()->IsDisposed());
338 xWinComponent
->dispose();
339 CPPUNIT_ASSERT(pVclWin
->getRef()->IsDisposed());
342 xWinComponent
.clear();
344 pVclWin
->disposeAndClear();
345 pVclWin
->assertDeleted();
350 CPPUNIT_TEST_SUITE_REGISTRATION(LifecycleTest
);
352 CPPUNIT_PLUGIN_IMPLEMENT();
354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */