include/test/a11y/accessibletestbase.hxx |    5 ---
 sw/qa/extras/accessibility/dialogs.cxx   |   28 ++++++++++----------
 test/qa/cppunit/dialog.cxx               |    8 ++---
 test/source/a11y/accessibletestbase.cxx  |   43 +++++++++++++++++++++++--------
 4 files changed, 51 insertions(+), 33 deletions(-)

New commits:
commit 655f6164e38c2f675beb5272fc6a9780f4767429
Author:     Colomban Wendling <cwendl...@hypra.fr>
AuthorDate: Tue Jan 31 11:25:28 2023 +0100
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Fri Mar 3 10:57:11 2023 +0000

    test: Run user dialog callback in idle time
    
    On e.g. Windows we need to let the dialogs fully finish starting up
    before we can properly interact with them, and especially close them
    again.
    
    We notice new dialogs with the WindowActivate event, but this will
    happen before the dialog is fully set up internally, leading to
    failures on Windows.  In practice, the WindowActivate event might be
    dispatched before the dialog setup function finishes, leading to an
    intermediate state at WindowActivate time.
    
    Work around this by running the user code in an idle timer in response
    to the WindowActivate event, so that the setup code can return before
    the callback is dispatched.
    
    Based on findings by Michael Weghorn, thanks!
    
    Change-Id: Ieecee09d84144570fe1943ca12dc1db6d9f64524
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146378
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/include/test/a11y/accessibletestbase.hxx 
b/include/test/a11y/accessibletestbase.hxx
index 0048edcd8589..5f5fb54aff4b 100644
--- a/include/test/a11y/accessibletestbase.hxx
+++ b/include/test/a11y/accessibletestbase.hxx
@@ -183,14 +183,11 @@ protected:
     /* Dialog handling */
     class Dialog : public test::EventPosterHelper
     {
-        friend class AccessibleTestBase;
-
     private:
         bool mbAutoClose;
 
-        Dialog(vcl::Window* pWindow, bool bAutoClose = true);
-
     public:
+        Dialog(vcl::Window* pWindow, bool bAutoClose = true);
         virtual ~Dialog();
 
         void setAutoClose(bool bAutoClose) { mbAutoClose = bAutoClose; }
diff --git a/sw/qa/extras/accessibility/dialogs.cxx 
b/sw/qa/extras/accessibility/dialogs.cxx
index 13c2fd0cb750..e6e3ac84c068 100644
--- a/sw/qa/extras/accessibility/dialogs.cxx
+++ b/sw/qa/extras/accessibility/dialogs.cxx
@@ -17,8 +17,8 @@
 
 using namespace css;
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(_WIN32) && !defined(MACOSX)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
BasicTestSpecialCharactersDialog)
 {
     load(u"private:factory/swriter");
@@ -64,8 +64,8 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
BasicTestSpecialCharactersDialo
 }
 #endif
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(_WIN32) && !defined(MACOSX)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 /* checks for the fix from https://gerrit.libreoffice.org/c/core/+/147660 */
 CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
TestSpecialCharactersDialogFocus)
 {
@@ -98,8 +98,8 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
TestSpecialCharactersDialogFocu
 }
 #endif
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(_WIN32) && !defined(MACOSX)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestHyperlinkDialog)
 {
     load(u"private:factory/swriter");
@@ -125,8 +125,8 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
BasicTestHyperlinkDialog)
 }
 #endif
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(_WIN32) && !defined(MACOSX)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestBookmarkDialog)
 {
     load(u"private:factory/swriter");
@@ -152,8 +152,8 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
BasicTestBookmarkDialog)
 }
 #endif
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(_WIN32) && !defined(MACOSX)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestSectionDialog)
 {
     load(u"private:factory/swriter");
@@ -173,8 +173,8 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
BasicTestSectionDialog)
 }
 #endif
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(_WIN32) && !defined(MACOSX)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestFontworkDialog)
 {
     load(u"private:factory/swriter");
@@ -197,8 +197,8 @@ CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, 
BasicTestFontworkDialog)
 }
 #endif
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(_WIN32) && !defined(MACOSX)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestFrameDialog)
 {
     load(u"private:factory/swriter");
diff --git a/test/qa/cppunit/dialog.cxx b/test/qa/cppunit/dialog.cxx
index c3f68a8f0e4e..0e188d52aa85 100644
--- a/test/qa/cppunit/dialog.cxx
+++ b/test/qa/cppunit/dialog.cxx
@@ -9,8 +9,8 @@
 
 #include <test/a11y/accessibletestbase.hxx>
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(MACOSX) && !defined(_WIN32)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 /* Checks an unexpected dialog opening (instead of the expected one) is 
properly caught, as it would
  * otherwise block the test potentially indefinitely */
 CPPUNIT_TEST_FIXTURE(test::AccessibleTestBase, SelfTestIncorrectDialog)
@@ -29,8 +29,8 @@ CPPUNIT_TEST_FIXTURE(test::AccessibleTestBase, 
SelfTestIncorrectDialog)
 }
 #endif
 
-// FIXME: dialog doesn't pop up on macos and doesn't close on win32...
-#if !defined(MACOSX) && !defined(_WIN32)
+// FIXME: dialog doesn't pop up on macos...
+#if !defined(MACOSX)
 /* Checks that an exception in the dialog callback code is properly handled 
and won't disturb
  * subsequent tests if caught -- especially that DialogWaiter::waitEndDialog() 
won't timeout. */
 CPPUNIT_TEST_FIXTURE(test::AccessibleTestBase, SelfTestThrowInDialogCallback)
diff --git a/test/source/a11y/accessibletestbase.cxx 
b/test/source/a11y/accessibletestbase.cxx
index 579d4ba2bfd4..bcfdcc89db1d 100644
--- a/test/source/a11y/accessibletestbase.cxx
+++ b/test/source/a11y/accessibletestbase.cxx
@@ -27,6 +27,7 @@
 #include <com/sun/star/uno/RuntimeException.hpp>
 #include <com/sun/star/util/XCloseable.hpp>
 
+#include <vcl/idle.hxx>
 #include <vcl/scheduler.hxx>
 #include <vcl/svapp.hxx>
 #include <vcl/window.hxx>
@@ -393,6 +394,9 @@ test::AccessibleTestBase::awaitDialog(const 
std::u16string_view name,
         std::function<void(Dialog&)> mCallback;
         bool mbAutoClose;
         Timer maTimeoutTimer;
+        Idle maIdleHandler;
+
+        std::unique_ptr<Dialog> mxDialog;
 
     public:
         virtual ~ListenerHelper()
@@ -400,6 +404,7 @@ test::AccessibleTestBase::awaitDialog(const 
std::u16string_view name,
             Application::SetDialogCancelMode(miPreviousDialogCancelMode);
             Application::RemoveEventListener(mLink);
             maTimeoutTimer.Stop();
+            maIdleHandler.Stop();
         }
 
         ListenerHelper(const std::u16string_view& name, 
std::function<void(Dialog&)> callback,
@@ -409,6 +414,7 @@ test::AccessibleTestBase::awaitDialog(const 
std::u16string_view name,
             , mCallback(callback)
             , mbAutoClose(bAutoClose)
             , maTimeoutTimer("workaround timer if we don't catch 
WindowActivate")
+            , maIdleHandler("runs user callback in idle time")
         {
             mLink = LINK(this, ListenerHelper, eventListener);
             Application::AddEventListener(mLink);
@@ -417,6 +423,9 @@ test::AccessibleTestBase::awaitDialog(const 
std::u16string_view name,
             maTimeoutTimer.SetTimeout(60000);
             maTimeoutTimer.Start();
 
+            maIdleHandler.SetInvokeHandler(LINK(this, ListenerHelper, 
idleHandler));
+            maIdleHandler.SetPriority(TaskPriority::DEFAULT_IDLE);
+
             miPreviousDialogCancelMode = Application::GetDialogCancelMode();
             Application::SetDialogCancelMode(DialogCancelMode::Off);
         }
@@ -458,42 +467,54 @@ test::AccessibleTestBase::awaitDialog(const 
std::u16string_view name,
             if (!pWin->IsDialog())
                 return;
 
-            mbWaitingForDialog = false;
-
             // remove ourselves, we don't want to run again
             Application::RemoveEventListener(mLink);
+
+            mxDialog = std::make_unique<Dialog>(pWin, true);
+
+            maIdleHandler.Start();
+        }
+
+        // mimic IMPL_LINK inline
+        static void LinkStubidleHandler(void* instance, Timer* idle)
+        {
+            static_cast<ListenerHelper*>(instance)->idleHandler(idle);
+        }
+
+        void idleHandler(Timer*)
+        {
+            mbWaitingForDialog = false;
+
             maTimeoutTimer.ClearInvokeHandler();
             maTimeoutTimer.Stop();
 
-            /* bind the dialog before checking its name so auto-close can kick 
in if anything
-             * fails/throws */
-            Dialog dialog(pWin, true);
-
             /* The popping up dialog ought to be the right one, or something's 
fishy and
              * we're bound to failure (e.g. waiting on a dialog that either 
will never come, or
              * that will not run after the current one -- deadlock style) */
-            if (msName != pWin->GetText())
+            if (msName != mxDialog->getWindow()->GetText())
             {
                 mpException = 
std::make_exception_ptr(css::uno::RuntimeException(
-                    "Unexpected dialog '" + pWin->GetText() + "' opened 
instead of the expected '"
-                    + msName + "'"));
+                    "Unexpected dialog '" + mxDialog->getWindow()->GetText()
+                    + "' opened instead of the expected '" + msName + "'"));
             }
             else
             {
                 std::cout << "found dialog, calling user callback" << 
std::endl;
 
                 // set the real requested auto close now we're just calling 
the user callback
-                dialog.setAutoClose(mbAutoClose);
+                mxDialog->setAutoClose(mbAutoClose);
 
                 try
                 {
-                    mCallback(dialog);
+                    mCallback(*mxDialog);
                 }
                 catch (...)
                 {
                     mpException = std::current_exception();
                 }
             }
+
+            mxDialog.reset();
         }
 
     public:

Reply via email to