From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- vcl/qa/cppunit/lifecycle.cxx | 357 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 vcl/qa/cppunit/lifecycle.cxx (limited to 'vcl/qa/cppunit/lifecycle.cxx') diff --git a/vcl/qa/cppunit/lifecycle.cxx b/vcl/qa/cppunit/lifecycle.cxx new file mode 100644 index 000000000..a4a3f5d9e --- /dev/null +++ b/vcl/qa/cppunit/lifecycle.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class LifecycleTest : public test::BootstrapFixture +{ + void testWidgets(vcl::Window *pParent); + +public: + LifecycleTest() : BootstrapFixture(true, false) {} + + void testCast(); + void testVirtualDevice(); + void testMultiDispose(); + void testIsolatedWidgets(); + void testParentedWidgets(); + void testChildDispose(); + void testPostDispose(); + void testFocus(); + void testLeakage(); + void testToolkit(); + + CPPUNIT_TEST_SUITE(LifecycleTest); + CPPUNIT_TEST(testCast); + CPPUNIT_TEST(testVirtualDevice); + CPPUNIT_TEST(testMultiDispose); + CPPUNIT_TEST(testIsolatedWidgets); + CPPUNIT_TEST(testParentedWidgets); + CPPUNIT_TEST(testChildDispose); + CPPUNIT_TEST(testPostDispose); + CPPUNIT_TEST(testFocus); + CPPUNIT_TEST(testLeakage); + CPPUNIT_TEST(testToolkit); + CPPUNIT_TEST_SUITE_END(); +}; + +// A compile time sanity check +void LifecycleTest::testCast() +{ + ScopedVclPtrInstance< PushButton > xButton( nullptr, 0 ); + ScopedVclPtr xWindow(xButton); + + ScopedVclPtrInstance< MetricField > xField( nullptr, 0 ); + ScopedVclPtr xSpin(xField); + ScopedVclPtr xEdit(xField); + +// the following line should NOT compile +// VclPtr xButton2(xWindow); +} + +void LifecycleTest::testVirtualDevice() +{ + VclPtr pVDev = VclPtr< VirtualDevice >::Create(); + ScopedVclPtrInstance< VirtualDevice > pVDev2; + VclPtrInstance pVDev3; + VclPtrInstance pVDev4(DeviceFormat::BITMASK); + CPPUNIT_ASSERT(!!pVDev && !!pVDev2 && !!pVDev3 && !!pVDev4); + pVDev.disposeAndClear(); + pVDev4.disposeAndClear(); +} + +void LifecycleTest::testMultiDispose() +{ + VclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + xWin->disposeOnce(); + xWin->disposeOnce(); + xWin->disposeOnce(); + CPPUNIT_ASSERT(!xWin->GetWindow(GetWindowType::Parent)); + CPPUNIT_ASSERT(!xWin->GetChild(0)); + CPPUNIT_ASSERT_EQUAL(static_cast(0), xWin->GetChildCount()); +} + +void LifecycleTest::testWidgets(vcl::Window *pParent) +{ + { + ScopedVclPtrInstance< PushButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< OKButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< CancelButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< HelpButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + + // Some widgets really insist on adoption. + if (pParent) + { + { + ScopedVclPtrInstance< CheckBox > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< Edit > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< ComboBox > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< RadioButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + } +} + +void LifecycleTest::testIsolatedWidgets() +{ + testWidgets(nullptr); +} + +void LifecycleTest::testParentedWidgets() +{ + ScopedVclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + xWin->Show(); + testWidgets(xWin); +} + +namespace { + +class DisposableChild : public vcl::Window +{ +public: + explicit DisposableChild(vcl::Window *pParent) : vcl::Window(pParent) {} + virtual ~DisposableChild() override + { + disposeOnce(); + } +}; + +} + +void LifecycleTest::testChildDispose() +{ + VclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + VclPtrInstance< DisposableChild > xChild( xWin.get() ); + xWin->Show(); + xChild->disposeOnce(); + xWin->disposeOnce(); +} + +void LifecycleTest::testPostDispose() +{ + VclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + xWin->disposeOnce(); + + // check selected methods continue to work post-dispose + CPPUNIT_ASSERT(!xWin->GetParent()); + xWin->Show(); + CPPUNIT_ASSERT(!xWin->IsReallyShown()); + CPPUNIT_ASSERT(!xWin->IsEnabled()); + CPPUNIT_ASSERT(!xWin->IsInputEnabled()); + CPPUNIT_ASSERT(!xWin->GetChild(0)); + CPPUNIT_ASSERT(!xWin->GetWindow(GetWindowType::Parent)); +} + +namespace { + +class FocusCrashPostDispose : public TabControl +{ +public: + explicit FocusCrashPostDispose(vcl::Window *pParent) : + TabControl(pParent, 0) + { + } + virtual bool PreNotify( NotifyEvent& ) override + { + return false; + } + virtual bool EventNotify( NotifyEvent& ) override + { + return false; + } + virtual void GetFocus() override + { + CPPUNIT_FAIL("get focus"); + } + virtual void LoseFocus() override + { + CPPUNIT_FAIL("this should never be called"); + } +}; + +} + +void LifecycleTest::testFocus() +{ + ScopedVclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + ScopedVclPtrInstance< FocusCrashPostDispose > xChild(xWin); + xWin->Show(); + xChild->GrabFocus(); + // process asynchronous ToTop + Scheduler::ProcessTaskScheduling(); + // FIXME: really awful to test focus issues without showing windows. + // CPPUNIT_ASSERT(xChild->HasFocus()); +} + +namespace { + +template +class LeakTestClass : public vcl_type +{ + bool &mrDeleted; +public: + template + LeakTestClass(bool &bDeleted, Arg &&... arg) : + vcl_type(std::forward(arg)...), + mrDeleted(bDeleted) + { + mrDeleted = false; + } + ~LeakTestClass() + { + mrDeleted = true; + } +}; + +class LeakTestObject +{ + bool mbDeleted; + VclPtr mxRef; + void *mpRef; + LeakTestObject() + : mbDeleted(false) + , mpRef(nullptr) + { + } +public: + template static LeakTestObject * + Create(Arg &&... arg) + { + LeakTestObject *pNew = new LeakTestObject(); + pNew->mxRef = VclPtr< LeakTestClass< vcl_type > >::Create( pNew->mbDeleted, + std::forward(arg)...); + pNew->mpRef = static_cast(static_cast(pNew->mxRef)); + return pNew; + } + const VclPtr& getRef() const { return mxRef; } + void disposeAndClear() + { + mxRef.disposeAndClear(); + } + void assertDeleted() + { + if (!mbDeleted) + { + OUStringBuffer aMsg = "Type '"; + vcl::Window *pWin = static_cast(mpRef); + aMsg.appendAscii(typeid(*pWin).name()); + aMsg.append("' not freed after dispose"); + CPPUNIT_FAIL(OUStringToOString(aMsg.makeStringAndClear(), + RTL_TEXTENCODING_UTF8).getStr()); + } + } +}; + +} + +void LifecycleTest::testLeakage() +{ + std::vector aObjects; + + // Create objects + aObjects.push_back(LeakTestObject::Create(nullptr, WB_APP|WB_STDWORK)); + VclPtr xParent = aObjects.back()->getRef(); + + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + + { // something that looks like a dialog + aObjects.push_back(LeakTestObject::Create(xParent,WB_CLIPCHILDREN|WB_MOVEABLE|WB_3DLOOK|WB_CLOSEABLE|WB_SIZEABLE)); + VclPtr xDlgParent = aObjects.back()->getRef(); + aObjects.push_back(LeakTestObject::Create(xDlgParent)); + VclPtr xVBox = aObjects.back()->getRef(); + aObjects.push_back(LeakTestObject::Create(xVBox)); + } + + aObjects.push_back(LeakTestObject::Create(xParent, "PrintProgressDialog", "vcl/ui/printprogressdialog.ui")); + xParent.clear(); + + for (auto i = aObjects.rbegin(); i != aObjects.rend(); ++i) + (*i)->getRef()->Show(); + + for (auto i = aObjects.rbegin(); i != aObjects.rend(); ++i) + (*i)->disposeAndClear(); + + for (auto i = aObjects.begin(); i != aObjects.end(); ++i) + (*i)->assertDeleted(); + + for (auto i = aObjects.begin(); i != aObjects.end(); ++i) + delete *i; +} + +void LifecycleTest::testToolkit() +{ + LeakTestObject *pVclWin = LeakTestObject::Create(nullptr, WB_APP|WB_STDWORK); + css::uno::Reference xWindow(pVclWin->getRef()->GetComponentInterface(), css::uno::UNO_QUERY); + CPPUNIT_ASSERT(xWindow.is()); + + // test UNO dispose + css::uno::Reference xWinComponent = xWindow; + CPPUNIT_ASSERT(xWinComponent.is()); + CPPUNIT_ASSERT(!pVclWin->getRef()->IsDisposed()); + xWinComponent->dispose(); + CPPUNIT_ASSERT(pVclWin->getRef()->IsDisposed()); + + // test UNO cleanup + xWinComponent.clear(); + xWindow.clear(); + pVclWin->disposeAndClear(); + pVclWin->assertDeleted(); + + delete pVclWin; +} + +CPPUNIT_TEST_SUITE_REGISTRATION(LifecycleTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3