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 <unotest/filters-test.hxx>
11 #include <test/bootstrapfixture.hxx>
13 #include <vcl/wrkwin.hxx>
14 #include <vcl/button.hxx>
15 #include <vcl/edit.hxx>
16 #include <vcl/combobox.hxx>
17 #include <vcl/field.hxx>
18 #include <vcl/virdev.hxx>
19 #include <vcl/tabctrl.hxx>
20 #include <vcl/dialog.hxx>
21 #include <vcl/layout.hxx>
22 #include <vcl/svapp.hxx>
23 #include <com/sun/star/awt/XWindow.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
);
81 void LifecycleTest::testMultiDispose()
83 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
84 CPPUNIT_ASSERT(xWin
.get() != nullptr);
88 CPPUNIT_ASSERT(xWin
->GetWindow(GetWindowType::Parent
) == nullptr);
89 CPPUNIT_ASSERT(xWin
->GetChild(0) == nullptr);
90 CPPUNIT_ASSERT(xWin
->GetChildCount() == 0);
93 void LifecycleTest::testWidgets(vcl::Window
*pParent
)
95 { ScopedVclPtrInstance
< PushButton
> aPtr( pParent
); }
96 { ScopedVclPtrInstance
< OKButton
> aPtr( pParent
); }
97 { ScopedVclPtrInstance
< CancelButton
> aPtr( pParent
); }
98 { ScopedVclPtrInstance
< HelpButton
> aPtr( pParent
); }
100 // Some widgets really insist on adoption.
103 { ScopedVclPtrInstance
< CheckBox
> aPtr( pParent
); }
104 { ScopedVclPtrInstance
< Edit
> aPtr( pParent
); }
105 { ScopedVclPtrInstance
< ComboBox
> aPtr( pParent
); }
106 { ScopedVclPtrInstance
< RadioButton
> aPtr( pParent
); }
110 void LifecycleTest::testIsolatedWidgets()
112 testWidgets(nullptr);
115 void LifecycleTest::testParentedWidgets()
117 ScopedVclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
118 CPPUNIT_ASSERT(xWin
.get() != nullptr);
123 class DisposableChild
: public vcl::Window
126 explicit DisposableChild(vcl::Window
*pParent
) : vcl::Window(pParent
) {}
127 virtual ~DisposableChild() override
133 void LifecycleTest::testChildDispose()
135 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
136 CPPUNIT_ASSERT(xWin
.get() != nullptr);
137 VclPtrInstance
< DisposableChild
> xChild( xWin
.get() );
139 xChild
->disposeOnce();
143 void LifecycleTest::testPostDispose()
145 VclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
148 // check selected methods continue to work post-dispose
149 CPPUNIT_ASSERT(!xWin
->GetParent());
151 CPPUNIT_ASSERT(!xWin
->IsReallyShown());
152 CPPUNIT_ASSERT(!xWin
->IsEnabled());
153 CPPUNIT_ASSERT(!xWin
->IsInputEnabled());
154 CPPUNIT_ASSERT(!xWin
->GetChild(0));
155 CPPUNIT_ASSERT(!xWin
->GetWindow(GetWindowType::Parent
));
158 class FocusCrashPostDispose
: public TabControl
161 explicit FocusCrashPostDispose(vcl::Window
*pParent
) :
162 TabControl(pParent
, 0)
165 virtual bool PreNotify( NotifyEvent
& ) override
169 virtual bool EventNotify( NotifyEvent
& ) override
173 virtual void GetFocus() override
175 CPPUNIT_FAIL("get focus");
177 virtual void LoseFocus() override
179 CPPUNIT_FAIL("this should never be called");
183 void LifecycleTest::testFocus()
185 ScopedVclPtrInstance
<WorkWindow
> xWin(nullptr, WB_APP
|WB_STDWORK
);
186 ScopedVclPtrInstance
< FocusCrashPostDispose
> xChild(xWin
);
189 // process asynchronous ToTop
190 Scheduler::ProcessTaskScheduling(false);
191 // FIXME: really awful to test focus issues without showing windows.
192 // CPPUNIT_ASSERT(xChild->HasFocus());
195 template <class vcl_type
>
196 class LeakTestClass
: public vcl_type
200 template<typename
... Arg
>
201 LeakTestClass(bool &bDeleted
, Arg
&&... arg
) :
202 vcl_type(std::forward
<Arg
>(arg
)...),
216 VclPtr
<vcl::Window
> mxRef
;
224 template<typename vcl_type
, typename
... Arg
> static LeakTestObject
*
225 Create(Arg
&&... arg
)
227 LeakTestObject
*pNew
= new LeakTestObject();
228 pNew
->mxRef
= VclPtr
< LeakTestClass
< vcl_type
> >::Create( pNew
->mbDeleted
,
229 std::forward
<Arg
>(arg
)...);
230 pNew
->mpRef
= static_cast<void *>(static_cast<vcl::Window
*>(pNew
->mxRef
));
233 const VclPtr
<vcl::Window
>& getRef() { return mxRef
; }
234 void disposeAndClear()
236 mxRef
.disposeAndClear();
242 OUStringBuffer aMsg
= "Type '";
243 vcl::Window
*pWin
= static_cast<vcl::Window
*>(mpRef
);
244 aMsg
.appendAscii(typeid(*pWin
).name());
245 aMsg
.append("' not freed after dispose");
246 CPPUNIT_FAIL(OUStringToOString(aMsg
.makeStringAndClear(),
247 RTL_TEXTENCODING_UTF8
).getStr());
252 void LifecycleTest::testLeakage()
254 std::vector
<LeakTestObject
*> aObjects
;
257 aObjects
.push_back(LeakTestObject::Create
<WorkWindow
>(nullptr, WB_APP
|WB_STDWORK
));
258 VclPtr
<vcl::Window
> xParent
= aObjects
.back()->getRef();
260 aObjects
.push_back(LeakTestObject::Create
<PushButton
>(xParent
));
261 aObjects
.push_back(LeakTestObject::Create
<OKButton
>(xParent
));
262 aObjects
.push_back(LeakTestObject::Create
<CancelButton
>(xParent
));
263 aObjects
.push_back(LeakTestObject::Create
<HelpButton
>(xParent
));
264 aObjects
.push_back(LeakTestObject::Create
<CheckBox
>(xParent
));
265 aObjects
.push_back(LeakTestObject::Create
<Edit
>(xParent
));
266 aObjects
.push_back(LeakTestObject::Create
<ComboBox
>(xParent
));
267 aObjects
.push_back(LeakTestObject::Create
<RadioButton
>(xParent
));
269 { // something that looks like a dialog
270 aObjects
.push_back(LeakTestObject::Create
<Dialog
>(xParent
,WB_CLIPCHILDREN
|WB_MOVEABLE
|WB_3DLOOK
|WB_CLOSEABLE
|WB_SIZEABLE
));
271 VclPtr
<vcl::Window
> xDlgParent
= aObjects
.back()->getRef();
272 aObjects
.push_back(LeakTestObject::Create
<VclVBox
>(xDlgParent
));
273 VclPtr
<vcl::Window
> xVBox
= aObjects
.back()->getRef();
274 aObjects
.push_back(LeakTestObject::Create
<VclVButtonBox
>(xVBox
));
277 #if 0 // FIXME - would be good to get internal paths working.
278 aObjects
.push_back(LeakTestObject::Create
<ModelessDialog
>(xParent
, "PrintProgressDialog", "vcl/ui/printprogressdialog.ui"));
280 aObjects
.push_back(LeakTestObject::Create
<ModalDialog
>(xParent
));
283 for (auto i
= aObjects
.rbegin(); i
!= aObjects
.rend(); ++i
)
284 (*i
)->getRef()->Show();
286 for (auto i
= aObjects
.rbegin(); i
!= aObjects
.rend(); ++i
)
287 (*i
)->disposeAndClear();
289 for (auto i
= aObjects
.begin(); i
!= aObjects
.end(); ++i
)
290 (*i
)->assertDeleted();
292 for (auto i
= aObjects
.begin(); i
!= aObjects
.end(); ++i
)
296 void LifecycleTest::testToolkit()
298 LeakTestObject
*pVclWin
= LeakTestObject::Create
<WorkWindow
>(nullptr, WB_APP
|WB_STDWORK
);
299 css::uno::Reference
<css::awt::XWindow
> xWindow(pVclWin
->getRef()->GetComponentInterface(), css::uno::UNO_QUERY
);
300 CPPUNIT_ASSERT(xWindow
.is());
303 css::uno::Reference
<css::lang::XComponent
> xWinComponent(xWindow
, css::uno::UNO_QUERY
);
304 CPPUNIT_ASSERT(xWinComponent
.is());
305 CPPUNIT_ASSERT(!pVclWin
->getRef()->IsDisposed());
306 xWinComponent
->dispose();
307 CPPUNIT_ASSERT(pVclWin
->getRef()->IsDisposed());
310 xWinComponent
.clear();
312 pVclWin
->disposeAndClear();
313 pVclWin
->assertDeleted();
318 CPPUNIT_TEST_SUITE_REGISTRATION(LifecycleTest
);
320 CPPUNIT_PLUGIN_IMPLEMENT();
322 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */