From d766c2e77342ea3a3f6cb8f999d66569bf299d4e Mon Sep 17 00:00:00 2001
From: Christian Stenger <christian.stenger@nokia.com>
Date: Fri, 10 Feb 2012 16:25:08 +0100
Subject: [PATCH] Squish: Use single file for workarounds
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This would help to keep the normal tests clean
and mess up only a single file that contains all
workarounds.

Change-Id: Ic26e57bcd13663efe9c882c003909eb0caa6fe9e
Reviewed-by: Robert Löhning <robert.loehning@nokia.com>
Reviewed-by: Bill King <bill.king@nokia.com>
---
 tests/system/shared/qtcreator.py              |   1 +
 tests/system/shared/workarounds.py            | 182 ++++++++++++++++++
 .../tst_basic_cpp_support/test.py             |   3 +-
 .../suite_general/tst_select_all/test.py      |   3 +-
 4 files changed, 185 insertions(+), 4 deletions(-)
 create mode 100644 tests/system/shared/workarounds.py

diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py
index 7e7841afafd..29cbd7e305a 100644
--- a/tests/system/shared/qtcreator.py
+++ b/tests/system/shared/qtcreator.py
@@ -22,6 +22,7 @@ source("../../shared/editor_utils.py")
 source("../../shared/project_explorer.py")
 source("../../shared/hook_utils.py")
 source("../../shared/debugger.py")
+source("../../shared/workarounds.py")
 
 def waitForCleanShutdown(timeOut=10):
     appCtxt = currentApplicationContext()
diff --git a/tests/system/shared/workarounds.py b/tests/system/shared/workarounds.py
new file mode 100644
index 00000000000..c665a7540de
--- /dev/null
+++ b/tests/system/shared/workarounds.py
@@ -0,0 +1,182 @@
+import urllib2
+import re
+
+JIRA_URL='https://bugreports.qt-project.org/browse'
+
+class JIRA:
+    __instance__ = None
+
+    # Helper class
+    class Bug:
+        CREATOR = 'QTCREATORBUG'
+        SIMULATOR = 'QTSIM'
+        SDK = 'QTSDK'
+        QT = 'QTBUG'
+        QT_QUICKCOMPONENTS = 'QTCOMPONENTS'
+
+    # constructor of JIRA
+    def __init__(self, number, bugType=Bug.CREATOR):
+        if JIRA.__instance__ == None:
+            JIRA.__instance__ = JIRA.__impl(number, bugType)
+            JIRA.__dict__['_JIRA__instance__'] = JIRA.__instance__
+        else:
+            JIRA.__instance__._bugType = bugType
+            JIRA.__instance__._number = number
+            JIRA.__instance__.__fetchStatusAndResolutionFromJira__()
+
+    # overriden to make it possible to use JIRA just like the
+    # underlying implementation (__impl)
+    def __getattr__(self, attr):
+        return getattr(self.__instance__, attr)
+
+    # overriden to make it possible to use JIRA just like the
+    # underlying implementation (__impl)
+    def __setattr__(self, attr, value):
+        return setattr(self.__instance__, attr, value)
+
+    # function to get an instance of the singleton
+    @staticmethod
+    def getInstance():
+        if '_JIRA__instance__' in JIRA.__dict__:
+            return JIRA.__instance__
+        else:
+            return JIRA.__impl(0, Bug.CREATOR)
+
+    # function to check if the given bug is open or not
+    @staticmethod
+    def isBugStillOpen(number, bugType=Bug.CREATOR):
+        tmpJIRA = JIRA(number, bugType)
+        return tmpJIRA.isOpen()
+
+    # function similar to performWorkaroundForBug - but it will execute the
+    # workaround (function) only if the bug is still open
+    # returns True if the workaround function has been executed, False otherwise
+    @staticmethod
+    def performWorkaroundIfStillOpen(number, bugType=Bug.CREATOR, *args):
+        if JIRA.isBugStillOpen(number, bugType):
+            return JIRA.performWorkaroundForBug(number, bugType, *args)
+        else:
+            test.warning("Bug is closed... skipping workaround!",
+                         "You should remove potential code inside performWorkaroundForBug()")
+            return False
+
+    # function that performs the workaround (function) for the given bug
+    # if the function needs additional arguments pass them as 3rd parameter
+    @staticmethod
+    def performWorkaroundForBug(number, bugType=Bug.CREATOR, *args):
+        functionToCall = JIRA.getInstance().__bugs__.get("%s-%d" % (bugType, number), None)
+        if functionToCall:
+            test.warning("Using workaround for %s-%d" % (bugType, number))
+            functionToCall(*args)
+            return True
+        else:
+            JIRA.getInstance()._exitFatal_(bugType, number)
+            return False
+
+    # implementation of JIRA singleton
+    class __impl:
+        # constructor of __impl
+        def __init__(self, number, bugType):
+            self._number = number
+            self._bugType = bugType
+            self._localOnly = os.getenv("SYSTEST_JIRA_NO_LOOKUP")=="1"
+            self.__initBugDict__()
+            self.__fetchStatusAndResolutionFromJira__()
+
+        # function to retrieve the status of the current bug
+        def getStatus(self):
+            return self._status
+
+        # function to retrieve the resolution of the current bug
+        def getResolution(self):
+            return self._resolution
+
+        # this function checks the resolution of the given bug
+        # and returns True if the bug can still be assumed as 'Open' and False otherwise
+        def isOpen(self):
+            # handle special cases
+            if self._resolution == None:
+                return True
+            if self._resolution in ('Duplicate', 'Moved', 'Incomplete', 'Cannot Reproduce', 'Invalid'):
+                test.warning("Resolution of bug is '%s' - assuming 'Open' for now." % self._resolution,
+                             "Please check the bugreport manually and update this test.")
+                return True
+            return self._resolution != 'Done'
+
+        # this function tries to fetch the status and resolution from JIRA for the given bug
+        # if this isn't possible or the lookup is disabled it does only check the internal
+        # dict whether a function for the given bug is deposited or not
+        def __fetchStatusAndResolutionFromJira__(self):
+            global JIRA_URL
+            data = None
+            if not self._localOnly:
+                try:
+                    bugReport = urllib2.urlopen('%s/%s-%d' % (JIRA_URL, self._bugType, self._number))
+                    data = bugReport.read()
+                except:
+                    data = self.__tryExternalTools__()
+                    if data == None:
+                        test.warning("Sorry, ssl module missing - cannot fetch data via HTTPS",
+                                     "Try to install the ssl module by yourself, or set the python "
+                                     "path inside SQUISHDIR/etc/paths.ini to use a python version with "
+                                     "ssl support OR install wget or curl to get rid of this warning!")
+                        self._localOnly = True
+            if data == None:
+                if '%s-%d' % (self._bugType, self._number) in self.__bugs__:
+                    test.warning("Using internal dict - bug status could have changed already",
+                                 "Please check manually!")
+                    self._status = None
+                    self._resolution = None
+                    return
+                else:
+                    test.fatal("No workaround function deposited for %s-%d" % (self._bugType, self._number))
+                    self._resolution = 'Done'
+                    return
+            else:
+                data = data.replace("\r", "").replace("\n", "")
+                resPattern = re.compile('<span\s+id="resolution-val".*?>(?P<resolution>.*?)</span>')
+                statPattern = re.compile('<span\s+id="status-val".*?>(.*?<img.*?>)?(?P<status>.*?)</span>')
+                status = statPattern.search(data)
+                resolution = resPattern.search(data)
+            if status:
+                self._status = status.group("status").strip()
+            else:
+                test.fatal("FATAL: Cannot get status of bugreport %s-%d" % (self._bugType, self._number),
+                           "Looks like JIRA has changed.... Please verify!")
+                self._status = None
+            if resolution:
+                self._resolution = resolution.group("resolution").strip()
+            else:
+                test.fatal("FATAL: Cannot get resolution of bugreport %s-%d" % (self._bugType, self._number),
+                           "Looks like JIRA has changed.... Please verify!")
+                self._resolution = None
+
+        # simple helper function - used as fallback if python has no ssl support
+        # tries to find curl or wget in PATH and fetches data with it instead of
+        # using urllib2
+        def __tryExternalTools__(self):
+            global JIRA_URL
+            cmdAndArgs = { 'curl':'-k', 'wget':'-qO-' }
+            for call in cmdAndArgs:
+                prog = which(call)
+                if prog:
+                    return getOutputFromCmdline("%s %s %s/%s-%d" % (prog, cmdAndArgs[call], JIRA_URL, self._bugType, self._number))
+            return None
+
+        # this function initializes the bug dict for localOnly usage and
+        # for later lookup which function to call for which bug
+        # ALWAYS update this dict when adding a new function for a workaround!
+        def __initBugDict__(self):
+            self.__bugs__= {
+                            'QTCREATORBUG-6918':self._workaroundCreator_MacEditorFocus_,
+                            'QTCREATORBUG-6953':self._workaroundCreator_MacEditorFocus_
+                            }
+        # helper function - will be called if no workaround for the requested bug is deposited
+        def _exitFatal_(self, bugType, number):
+            test.fatal("No workaround found for bug %s-%d" % (bugType, number))
+
+############### functions that hold workarounds #################################
+
+        def _workaroundCreator_MacEditorFocus_(self, *args):
+            editor = args[0]
+            nativeMouseClick(editor.mapToGlobal(QPoint(50, 50)).x, editor.mapToGlobal(QPoint(50, 50)).y, Qt.LeftButton)
diff --git a/tests/system/suite_general/tst_basic_cpp_support/test.py b/tests/system/suite_general/tst_basic_cpp_support/test.py
index 65bcf69c996..76adf075793 100644
--- a/tests/system/suite_general/tst_basic_cpp_support/test.py
+++ b/tests/system/suite_general/tst_basic_cpp_support/test.py
@@ -25,8 +25,7 @@ def main():
 #    - Press F2 or select from the menu: Tools / C++ / Follow Symbol under Cursor
 #    Creator will show you the declaration of the variable.
 
-    # workaround because of QTCREATORBUG-6953
-    nativeMouseClick(cppwindow.mapToGlobal(QPoint(50, 50)).x, cppwindow.mapToGlobal(QPoint(50, 50)).y, Qt.LeftButton)
+    JIRA.performWorkaroundIfStillOpen(6953, JIRA.Bug.CREATOR, cppwindow)
     type(cppwindow, "<Ctrl+F>")
     type(waitForObject(":*Qt Creator.findEdit_Utils::FilterLineEdit"), "    xi")
     type(waitForObject(":*Qt Creator.findEdit_Utils::FilterLineEdit"), "<Return>")
diff --git a/tests/system/suite_general/tst_select_all/test.py b/tests/system/suite_general/tst_select_all/test.py
index fa9d9c25092..690bebdfe21 100644
--- a/tests/system/suite_general/tst_select_all/test.py
+++ b/tests/system/suite_general/tst_select_all/test.py
@@ -25,8 +25,7 @@ def main():
         selectFromFileDialog(currentFile)
         editor = waitForObject("{type='%s' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}"
                                % filesAndEditors[currentFile], 20000)
-        # needed on Mac because of QTCREATORBUG-6918
-        nativeMouseClick(editor.mapToGlobal(QPoint(50, 50)).x, editor.mapToGlobal(QPoint(50, 50)).y, Qt.LeftButton)
+        JIRA.performWorkaroundIfStillOpen(6918, JIRA.Bug.CREATOR, editor)
         for key in ["<Up>", "<Down>", "<Left>", "<Right>"]:
             test.log("Selecting everything")
             invokeMenuItem("Edit", "Select All")
-- 
GitLab