build fix
[LibreOffice.git] / vcl / qa / cppunit / lifecycle.cxx
blob8177cc805d0023de6080c0f089d38ea0788beaf7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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);
30 public:
31 LifecycleTest() : BootstrapFixture(true, false) {}
33 void testCast();
34 void testVirtualDevice();
35 void testMultiDispose();
36 void testIsolatedWidgets();
37 void testParentedWidgets();
38 void testChildDispose();
39 void testPostDispose();
40 void testFocus();
41 void testLeakage();
42 void testToolkit();
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);
85 xWin->disposeOnce();
86 xWin->disposeOnce();
87 xWin->disposeOnce();
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.
101 if (pParent)
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);
119 xWin->Show();
120 testWidgets(xWin);
123 class DisposableChild : public vcl::Window
125 public:
126 explicit DisposableChild(vcl::Window *pParent) : vcl::Window(pParent) {}
127 virtual ~DisposableChild() override
129 disposeOnce();
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() );
138 xWin->Show();
139 xChild->disposeOnce();
140 xWin->disposeOnce();
143 void LifecycleTest::testPostDispose()
145 VclPtrInstance<WorkWindow> xWin(nullptr, WB_APP|WB_STDWORK);
146 xWin->disposeOnce();
148 // check selected methods continue to work post-dispose
149 CPPUNIT_ASSERT(!xWin->GetParent());
150 xWin->Show();
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
160 public:
161 explicit FocusCrashPostDispose(vcl::Window *pParent) :
162 TabControl(pParent, 0)
165 virtual bool PreNotify( NotifyEvent& ) override
167 return false;
169 virtual bool EventNotify( NotifyEvent& ) override
171 return false;
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);
187 xWin->Show();
188 xChild->GrabFocus();
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
198 bool &mrDeleted;
199 public:
200 template<typename... Arg>
201 LeakTestClass(bool &bDeleted, Arg &&... arg) :
202 vcl_type(std::forward<Arg>(arg)...),
203 mrDeleted(bDeleted)
205 mrDeleted = false;
207 ~LeakTestClass()
209 mrDeleted = true;
213 class LeakTestObject
215 bool mbDeleted;
216 VclPtr<vcl::Window> mxRef;
217 void *mpRef;
218 LeakTestObject()
219 : mbDeleted(false)
220 , mpRef(nullptr)
223 public:
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));
231 return pNew;
233 const VclPtr<vcl::Window>& getRef() { return mxRef; }
234 void disposeAndClear()
236 mxRef.disposeAndClear();
238 void assertDeleted()
240 if (!mbDeleted)
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;
256 // Create objects
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"));
279 #endif
280 aObjects.push_back(LeakTestObject::Create<ModalDialog>(xParent));
281 xParent.clear();
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)
293 delete *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());
302 // test UNO dispose
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());
309 // test UNO cleanup
310 xWinComponent.clear();
311 xWindow.clear();
312 pVclWin->disposeAndClear();
313 pVclWin->assertDeleted();
315 delete pVclWin;
318 CPPUNIT_TEST_SUITE_REGISTRATION(LifecycleTest);
320 CPPUNIT_PLUGIN_IMPLEMENT();
322 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */