From 5f37dc12bb2854ae3bb9010ae392aa00d1c5a239 Mon Sep 17 00:00:00 2001
From: Roman Tolchenov <roman.tolchenov@stfc.ac.uk>
Date: Mon, 17 Dec 2018 10:58:15 +0000
Subject: [PATCH] A working workbench gui test. Re #24027

---
 buildconfig/CMake/FindPyUnitTest.cmake        |  8 +++-
 qt/applications/workbench/CMakeLists.txt      | 15 +++++++
 .../workbench/workbench/test/runner.py        | 16 ++++++++
 .../test/test_fit_interactive_tool.py         | 41 +++++++++++++++++++
 .../mantidqt/utils/qt/test/gui_test_runner.py |  9 ++--
 .../mantidqt/utils/qt/test/gui_window_test.py | 36 ++++++++++++++++
 .../mantidqt/widgets/fitpropertybrowser.py    |  9 ++--
 7 files changed, 126 insertions(+), 8 deletions(-)
 create mode 100644 qt/applications/workbench/workbench/test/runner.py
 create mode 100644 qt/applications/workbench/workbench/test/test_fit_interactive_tool.py

diff --git a/buildconfig/CMake/FindPyUnitTest.cmake b/buildconfig/CMake/FindPyUnitTest.cmake
index 5ac987e2e62..20725240b3f 100644
--- a/buildconfig/CMake/FindPyUnitTest.cmake
+++ b/buildconfig/CMake/FindPyUnitTest.cmake
@@ -24,7 +24,13 @@ function ( PYUNITTEST_ADD_TEST _test_src_dir _testname_prefix )
   if ( WIN32 )
     set ( _test_runner ${_test_runner}.bat )
   endif ()
-  set ( _test_runner_module ${CMAKE_SOURCE_DIR}/Framework/PythonInterface/test/testhelpers/testrunner.py )
+
+  if ( NOT PYUNITTEST_RUNNER )
+    set ( _test_runner_module ${CMAKE_SOURCE_DIR}/Framework/PythonInterface/test/testhelpers/testrunner.py )
+  else ()
+    set ( _test_runner_module ${PYUNITTEST_RUNNER} )
+  endif()
+
 
   # Environment
   if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
diff --git a/qt/applications/workbench/CMakeLists.txt b/qt/applications/workbench/CMakeLists.txt
index 323ecee823c..6da9e267956 100644
--- a/qt/applications/workbench/CMakeLists.txt
+++ b/qt/applications/workbench/CMakeLists.txt
@@ -29,9 +29,24 @@ set ( TEST_FILES
   workbench/widgets/plotselector/test/test_plotselector_view.py
 )
 
+set ( WORKBENCH_TEST_PY_FILES
+  workbench/test/test_fit_interactive_tool.py
+)
+
 set ( PYUNITTEST_RUN_SERIAL ON )
 set ( PYUNITTEST_QT_API pyqt5)
 pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR}
   workbench ${TEST_FILES}
 )
+
+if ( CMAKE_GENERATOR MATCHES "Visual Studio" OR CMAKE_GENERATOR MATCHES "Xcode" )
+  set ( PYUNITTEST_RUNNER ${CMAKE_BINARY_DIR}/bin/$<CONFIG>/workbench-script.pyw -x)
+else()
+  set ( PYUNITTEST_RUNNER ${CMAKE_BINARY_DIR}/bin/workbench.py -xq)
+endif()
+
+pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR}
+  workbench_gui ${WORKBENCH_TEST_PY_FILES}
+)
+
 # Not installed yet...
diff --git a/qt/applications/workbench/workbench/test/runner.py b/qt/applications/workbench/workbench/test/runner.py
new file mode 100644
index 00000000000..b315ffb1b1c
--- /dev/null
+++ b/qt/applications/workbench/workbench/test/runner.py
@@ -0,0 +1,16 @@
+# Mantid Repository : https://github.com/mantidproject/mantid
+#
+# Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory UKRI,
+#     NScD Oak Ridge National Laboratory, European Spallation Source
+#     & Institut Laue - Langevin
+# SPDX - License - Identifier: GPL - 3.0 +
+#  This file is part of the mantid workbench.
+#
+#
+from workbench.plotting.qappthreadcall import QAppThreadCall
+
+
+def run_gui_test(class_name):
+    def test():
+        class_name().run_all_tests()
+    QAppThreadCall(test)()
diff --git a/qt/applications/workbench/workbench/test/test_fit_interactive_tool.py b/qt/applications/workbench/workbench/test/test_fit_interactive_tool.py
new file mode 100644
index 00000000000..99cd29126e4
--- /dev/null
+++ b/qt/applications/workbench/workbench/test/test_fit_interactive_tool.py
@@ -0,0 +1,41 @@
+from __future__ import print_function
+
+from qtpy.QtCore import QPoint
+
+from mantid.simpleapi import *
+from mantidqt.utils.qt.test.gui_window_test import *
+
+from workbench.plotting.functions import plot
+from workbench.plotting.globalfiguremanager import GlobalFigureManager
+from workbench.test.runner import run_gui_test
+
+
+class TestFitPropertyBrowser(WorkbenchGuiTest):
+
+    def test_fit_range(self):
+        ws = Load(r'irs26176_graphite002_conv_1LFixF_s0_to_9_Result.nxs', OutputWorkspace='ws')
+        plot([ws], [1])
+        manager = GlobalFigureManager.get_active()
+        w = manager.window
+        trigger_action(find_action_with_text(w, 'Fit'))
+        yield 0.1
+        fit_browser = manager.fit_browser
+        start_x = fit_browser.startX()
+        start_x_pxl = fit_browser.tool.fit_start_x.get_x_in_pixels()
+        end_x = fit_browser.endX()
+        end_x_pxl = fit_browser.tool.fit_end_x.get_x_in_pixels()
+        self.assertAlmostEqual(start_x, 0.5318, 4)
+        self.assertAlmostEqual(end_x, 1.8186, 4)
+        pos = w._canvas.geometry().center()
+        canvas = w.childAt(pos)
+        pos.setX(fit_browser.tool.fit_start_x.get_x_in_pixels())
+        new_pos = pos + QPoint(100, 0)
+        yield drag_mouse(canvas, pos, new_pos)
+        self.assertAlmostEqual(fit_browser.startX(), start_x + 100.0 / (end_x_pxl - start_x_pxl) * (end_x - start_x), 2)
+        pos.setX(fit_browser.tool.fit_end_x.get_x_in_pixels())
+        new_pos = pos - QPoint(30, 0)
+        yield drag_mouse(canvas, pos, new_pos)
+        self.assertAlmostEqual(fit_browser.endX(), end_x - 30.0 / (end_x_pxl - start_x_pxl) * (end_x - start_x), 2)
+
+
+run_gui_test(TestFitPropertyBrowser)
diff --git a/qt/python/mantidqt/utils/qt/test/gui_test_runner.py b/qt/python/mantidqt/utils/qt/test/gui_test_runner.py
index 087dd39c39f..1999fc3ab26 100644
--- a/qt/python/mantidqt/utils/qt/test/gui_test_runner.py
+++ b/qt/python/mantidqt/utils/qt/test/gui_test_runner.py
@@ -80,7 +80,7 @@ class ScriptRunner(object):
             try:
                 if self.script_iter is None:
                     if self.close_on_finish:
-                        QMetaObject.invokeMethod(self.widget, 'close', Qt.QueuedConnection)
+                        app.exit()
                     return
                 # Run test script until the next 'yield'
                 ret = self.script_iter.next()
@@ -99,10 +99,11 @@ class ScriptRunner(object):
                     self.script_iter = None
                     self.script_timer.stop()
                     if self.close_on_finish:
-                        QMetaObject.invokeMethod(self.widget, 'close', Qt.QueuedConnection)
+                        app.exit()
             except Exception as e:
-                self.widget.close()
                 traceback.print_exc()
+                if self.close_on_finish:
+                    app.exit(1)
                 self.error = e
 
 
@@ -158,7 +159,7 @@ def open_in_window(widget_or_name, script, attach_debugger=True, pause=0, close_
     script_runner = None
     if script is not None:
         try:
-            timer = QTimer()
+            timer = QTimer(app)
             script_runner = ScriptRunner(script, widget, close_on_finish=close_on_finish, script_timer=timer, is_cli=is_cli)
             if pause != 0:
                 timer.setInterval(pause * 1000)
diff --git a/qt/python/mantidqt/utils/qt/test/gui_window_test.py b/qt/python/mantidqt/utils/qt/test/gui_window_test.py
index 16135f5b23f..d1c34c97f9b 100644
--- a/qt/python/mantidqt/utils/qt/test/gui_window_test.py
+++ b/qt/python/mantidqt/utils/qt/test/gui_window_test.py
@@ -14,6 +14,28 @@ from unittest import TestCase
 from mantidqt.utils.qt.test.gui_test_runner import open_in_window
 from qtpy.QtWidgets import QPushButton, QMenu, QAction, QApplication
 from qtpy.QtCore import Qt, QMetaObject
+from qtpy.QtTest import QTest
+
+
+def trigger_action(action):
+    QMetaObject.invokeMethod(action, 'trigger', Qt.QueuedConnection)
+
+
+def find_action_with_text(widget, text):
+    for action in widget.findChildren(QAction):
+        if action.text() == text:
+            return action
+    raise RuntimeError("Couldn't find action with text \"{}\"".format(text))
+
+
+def drag_mouse(widget, from_pos, to_pos):
+    QTest.mousePress(widget, Qt.LeftButton, Qt.NoModifier, from_pos)
+    yield
+    QTest.mouseMove(widget, from_pos)
+    yield 0.1
+    QTest.mouseMove(widget, to_pos)
+    yield
+    QTest.mouseRelease(widget, Qt.LeftButton, Qt.NoModifier, to_pos)
 
 
 class GuiTestBase(object):
@@ -46,6 +68,10 @@ class GuiTestBase(object):
         open_in_window(self.create_widget, self._call_test_method, attach_debugger=attach_debugger, pause=pause,
                        close_on_finish=close_on_finish)
 
+    def run_all_tests(self):
+        for test in inspect.getmembers(self, is_test_method):
+            self.run_test(method=test[0], close_on_finish=True)
+
     def get_child(self, child_class, name):
         children = self.widget.findChildren(child_class, name)
         if len(children) == 0:
@@ -115,3 +141,13 @@ class GuiWindowTest(TestCase, GuiTestBase):
             wrapped_name = '_' + name
             setattr(cls, wrapped_name, test[1])
             setattr(cls, name, make_test_wrapper(wrapped_name))
+
+    def runTest(self):
+        pass
+
+
+class WorkbenchGuiTest(GuiWindowTest):
+
+    def create_widget(self):
+        qapp = QApplication.instance()
+        return qapp.activeWindow()
diff --git a/qt/python/mantidqt/widgets/fitpropertybrowser.py b/qt/python/mantidqt/widgets/fitpropertybrowser.py
index 7541aa831b0..78e76b6bf78 100644
--- a/qt/python/mantidqt/widgets/fitpropertybrowser.py
+++ b/qt/python/mantidqt/widgets/fitpropertybrowser.py
@@ -85,9 +85,12 @@ class VerticalMarker(QObject):
         vertices[1] = self.x, y1
         self.ax.draw_artist(self.patch)
 
-    def is_above(self, x):
+    def get_x_in_pixels(self):
         x_pixels, _ = self.patch.get_transform().transform((self.x, 0))
-        return np.abs(x_pixels - x) < 3
+        return x_pixels
+
+    def is_above(self, x):
+        return np.abs(self.get_x_in_pixels() - x) < 3
 
     def on_click(self, x):
         if self.is_above(x):
@@ -116,7 +119,7 @@ class FitInteractiveTool(QObject):
         ax = canvas.figure.get_axes()[0]
         self.ax = ax
         xlim = ax.get_xlim()
-        dx = (xlim[1] - xlim[0]) / 5.
+        dx = (xlim[1] - xlim[0]) / 20.
         start_x = xlim[0] + dx
         end_x = xlim[1] - dx
         self.fit_start_x = VerticalMarker(canvas, start_x, 'green')
-- 
GitLab