summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Stenger <christian.stenger@nokia.com>2011-11-09 16:40:35 +0100
committerChristian Stenger <christian.stenger@nokia.com>2011-11-23 15:49:04 +0100
commit3089bd3f6c028c1b8b33cc9c1ba3c3fbedcac28c (patch)
tree5e0c80637755e106079b1501085ea223a21d7b91
parent6d36b5f71b60c5bf9d7fdfb828a0550c14526702 (diff)
downloadqt-creator-3089bd3f6c028c1b8b33cc9c1ba3c3fbedcac28c.tar.gz
Squish: Implements hooking into the subprocess
Change-Id: Ic1ae2a8341d01e179f9d52b7c7ad3cbe24995bd1 Reviewed-by: Robert Löhning <robert.loehning@nokia.com>
-rw-r--r--tests/system/README89
-rw-r--r--tests/system/objects.map3
-rw-r--r--tests/system/shared/hook_utils.py273
-rw-r--r--tests/system/shared/project.py3
-rw-r--r--tests/system/shared/project_explorer.py128
-rw-r--r--tests/system/shared/qtcreator.py2
-rw-r--r--tests/system/shared/qtquick.py23
-rw-r--r--tests/system/shared/utils.py13
-rw-r--r--tests/system/shared_data/qt_squish_mapping.tsv11
-rw-r--r--tests/system/suite_qtquick/tst_qtquick_creation/test.py21
10 files changed, 559 insertions, 7 deletions
diff --git a/tests/system/README b/tests/system/README
new file mode 100644
index 0000000000..972f8e2a84
--- /dev/null
+++ b/tests/system/README
@@ -0,0 +1,89 @@
+Preface
+-------
+The usage of the hook-into subprocess has following prerequisites:
+Either:
+ * have no firewall at all enabled (sure that's a bad idea)
+Or:
+ * have the Windows Firewall enabled (no other firewalls are handled by the scripts)
+ * run the Squish tests with administrator privileges
+ * additionally the UAC should be disabled, too
+
+Otherwise you'll have some trouble with popping up dialogs from the firewall.
+If you're using a different firewall - try to figure out and add a rule for this.
+
+
+Using the internal test data fallback
+-------------------------------------
+
+ * inside the shared_data folder a "standard" mapping file is located (qt_squish_mapping.tsv)
+ * this file defines currently some Squish versions that are available for usage
+ * all of the Squish versions mentioned in there should exist inside QTSDK/src/creator-test-data (see the file for naming the Squish versions) - of course this depends on the OS you're testing on
+
+Attention! This file will be updated with more columns (and rows) for making it possible to also test Debug builds or 64bit builds. So, even the path entries currently listed could change when this feature is implemented.
+
+
+Using QT_SQUISH_MAPFILE variable
+--------------------------------
+
+ * create a simple text file (UTF-8 encoded) that follows this scheme:
+
+ QtVersion mkspec Path
+
+ * QtVersion: only major and minor number will be used (e.g. 4.7, 4.8, 5.0)
+ * mkspec: a string holding the mkspec as it appears inside QTSDK/mkspec (or inside Qt Creator)
+ * Path: the path to the Squish directory that can be used with this combination of QtVersion and mkspec
+ * between QtVersion and mkspec as well as between mkspec and Path use whitespaces only
+ * lines STARTING with # within the first column will be ignored
+ * path can contain spaces as well as ~ (for the home directory)
+ * you can put any entry of a line into quotes (no matter whether single or double quotes)
+ * a line holding a mapping MUST start with a QtVersion entry in the first column
+
+Example 1: (using single space, no quoting)
+
+#qtversion mkspec path
+4.7<SP>win32-g++<SP>C:\Tools\Squish_MinGW
+4.7<SP>win32-msvc2008<SP>C:\Tools\Squish_MSVC9
+4.7<SP>win32-msvc2010<SP>C:\Tools\Squish_MSVC10
+4.8<SP>win32-g++<SP>C:\Tools\Squish_MinGW
+4.8<SP>win32-msvc2008<SP>C:\Tools\Squish_MSVC9
+4.8<SP>win32-msvc2010<SP>C:\Tools\Squish_MSVC10
+
+Example 2: (using mixed whitespaces, some quoting)
+
+#qtversion<TAB>mkspec<TAB><TAB><SP>path
+"4.7"<SP><TAB>win32-g++<TAB><TAB>'C:\Tools\Squish_MinGW'
+'4.7'<SP><TAB>'win32-msvc2008'<TAB>"C:\Tools\Squish_MSVC9"
+4.7<SP><SP><TAB>win32-msvc2010<TAB>C:\Tools\Squish_MSVC10
+"4.8"<SP><TAB>"win32-g++"<SP><SP><TAB>"C:\Tools\Squish_MinGW"
+'4.8'<SP><TAB>win32-msvc2008<SP><TAB>'C:\Tools\Squish_MSVC9'
+'4.8'<SP><TAB>win32-msvc2010<SP><TAB>C:\Tools\Squish_MSVC10
+
+Explanation: <SP> = space, <TAB> = tabulator
+
+ * after creating this file put it somewhere and define environment variable QT_SQUISH_MAPFILE to point directly to the file
+ * definition of this variable should be done BEFORE the test is started and can be done in various ways:
+ * declare this variable as a system environment variable (how to do this depends on the OS you're using) [recommended way]
+ * add this variable to the envvar file inside the directory holding the Squish test suites [please don't do this when pushing envvar back to git]
+ * you can also modify the os.environ dict inside the test script(s) but this has to be done, before the test tries to read the variable [best place would be right before/after the call to startApplication()]
+
+Hint: You can also use the provided tsv file as a template. Simply remove lines you're not needing and adjust the path entries to point to the correct paths on your system and you should be fine.
+
+Attention! The format of the file might slightly change as soon also Debug builds will be easily testable (and maybe again for 64bit builds)
+
+
+Preparation of the SQUISH directories
+-------------------------------------
+To make the hook-into sub-process really work you have to provide a modified Squish.
+
+Steps to set up the Squish directories on Windows:
+ * get the Squish version you need from froglogic.com
+ * extract the archive to place of your choice
+ * go to the bin directory of Squish and remove the following dll's:
+ * Qt3Support.dll
+ * QtCore4.dll
+ * QtGui4.dll
+ * QtNetwork4.dll
+ * QtSql4.dll
+ * QtXml4.dll
+
+You can additionally remove the complete ide folder as well as squishclassicide.exe and squishide.exe (to safe disk space).
diff --git a/tests/system/objects.map b/tests/system/objects.map
index 245d149064..dfc6fd961f 100644
--- a/tests/system/objects.map
+++ b/tests/system/objects.map
@@ -22,6 +22,7 @@
:Qt Creator.QtCreator.MenuBar_QMenuBar {name='QtCreator.MenuBar' type='QMenuBar' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.ReRun_QToolButton {toolTip='Re-run this run-configuration' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator.Stop_QToolButton {text='Stop' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
+:Qt Creator.scrollArea_QScrollArea {name='scrollArea' type='QScrollArea' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator_Core::Internal::MainWindow {type='Core::Internal::MainWindow' visible='1' windowTitle?='*Qt Creator'}
:Qt Creator_Core::Internal::OutputPaneToggleButton {occurrence='3' type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
:Qt Creator_CppEditor::Internal::CPPEditorWidget {type='CppEditor::Internal::CPPEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
@@ -51,4 +52,6 @@
:scrollArea.Qt Version:_QComboBox {aboveWidget=':scrollArea.Use Shadow Building_QCheckBox' container=':Qt Gui Application.scrollArea_QScrollArea' leftWidget=':scrollArea.Qt Version:_QLabel' type='QComboBox' unnamed='1' visible='1'}
:scrollArea.Qt Version:_QLabel {container=':Qt Gui Application.scrollArea_QScrollArea' text='Qt Version:' type='QLabel' unnamed='1' visible='1'}
:scrollArea.Use Shadow Building_QCheckBox {container=':Qt Gui Application.scrollArea_QScrollArea' text='Use Shadow Building' type='QCheckBox' unnamed='1' visible='1'}
+:scrollArea.qtVersionComboBox_QComboBox {container=':Qt Creator.scrollArea_QScrollArea' name='qtVersionComboBox' type='QComboBox' visible='1'}
+:scrollArea_QTableView {container=':Qt Creator.scrollArea_QScrollArea' type='QTableView' unnamed='1' visible='1'}
:sourceFileLineEdit_Utils::FileNameValidatingLineEdit {buddy=':Qt Gui Application.Source file:_QLabel' name='sourceFileLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1'}
diff --git a/tests/system/shared/hook_utils.py b/tests/system/shared/hook_utils.py
new file mode 100644
index 0000000000..300f5b8d63
--- /dev/null
+++ b/tests/system/shared/hook_utils.py
@@ -0,0 +1,273 @@
+import re
+# flag that caches the information whether Windows firewall is running or not
+fireWallState = None
+
+# this function modifies all necessary run settings to make it possible to hook into
+# the application compiled by Creator
+def modifyRunSettingsForHookInto(projectName, port):
+ prepareBuildSettings(1, 0)
+ # this uses the defaultQtVersion currently
+ switchViewTo(ViewConstants.PROJECTS)
+ switchToBuildOrRunSettingsFor(1, 0, ProjectSettings.BUILD)
+ qtVersionTT = str(waitForObject("{type='QComboBox' name='qtVersionComboBox' visible='1'}").toolTip)
+ mkspec = __getMkspec__(qtVersionTT)
+ qmakeVersion = __getQMakeVersion__(qtVersionTT)
+ qmakeLibPath = __getQMakeLibPath__(qtVersionTT)
+ qmakeBinPath = __getQMakeBinPath__(qtVersionTT)
+ switchToBuildOrRunSettingsFor(1, 0, ProjectSettings.RUN)
+ result = __configureCustomExecutable__(projectName, port, mkspec, qmakeVersion)
+ if result:
+ clickButton(waitForObject("{container=':Qt Creator.scrollArea_QScrollArea' text='Details' "
+ "type='Utils::DetailsButton' unnamed='1' visible='1' "
+ "leftWidget={type='QLabel' text='Using <b>Build Environment</b>' unnamed='1' visible='1'}}"))
+ envVarsTableView = waitForObject("{type='QTableView' visible='1' unnamed='1'}")
+ model = envVarsTableView.model()
+ for row in range(model.rowCount()):
+ # get var name
+ index = model.index(row, 0)
+ envVarsTableView.scrollTo(index)
+ varName = str(model.data(index).toString())
+ # if its a special SQUISH var simply unset it
+ if varName == "PATH":
+ currentItem = __doubleClickQTableView__(row, 1)
+ test.log("replacing PATH with '%s'" % qmakeBinPath)
+ replaceEditorContent(currentItem, qmakeBinPath)
+ elif varName.find("SQUISH") == 0:
+ if varName == "SQUISH_LIBQTDIR":
+ currentItem = __doubleClickQTableView__(row, 1)
+ if platform.system() in ('Microsoft', 'Windows'):
+ replacement = qmakeBinPath
+ else:
+ replacement = qmakeLibPath
+ test.log("Changing SQUISH_LIBQTDIR",
+ "Replacing '%s' with '%s'" % (currentItem.text, replacement))
+ replaceEditorContent(currentItem, replacement)
+ else:
+ mouseClick(waitForObject("{container=':scrollArea_QTableView' "
+ "type='QModelIndex' row='%d' column='1'}" % row), 5, 5, 0, Qt.LeftButton)
+ clickButton(waitForObject("{type='QPushButton' text='Unset' unnamed='1' visible='1'}"))
+ #test.log("Unsetting %s for run" % varName)
+ switchViewTo(ViewConstants.EDIT)
+ return result
+
+# helper that double clicks the table view at specified row and column
+# returns the QExpandingLineEdit (the editable table cell)
+def __doubleClickQTableView__(row, column):
+ doubleClick(waitForObject("{container=':scrollArea_QTableView' "
+ "type='QModelIndex' row='%d' column='%d'}" % (row, column)), 5, 5, 0, Qt.LeftButton)
+ return waitForObject("{type='QExpandingLineEdit' visible='1' unnamed='1'}")
+
+# this function configures the custom executable onto the run settings page (using startaut from Squish)
+def __configureCustomExecutable__(projectName, port, mkspec, qmakeVersion):
+ startAUT = getSquishPath(mkspec, qmakeVersion)
+ if startAUT == None:
+ test.warning("Something went wrong determining the right Squish for %s / %s combination - "
+ "using fallback without hooking into subprocess." % (qmakeVersion, mkspec))
+ return False
+ else:
+ startAUT = os.path.abspath(startAUT + "/bin/startaut")
+ if platform.system() in ('Microsoft', 'Windows'):
+ startAUT += ".exe"
+ if not os.path.exists(startAUT):
+ test.warning("Configured Squish directory seems to be missing - using fallback without hooking into subprocess.",
+ "Failed to find '%s'" % startAUT)
+ return False
+ clickButton("{container=':Qt Creator.scrollArea_QScrollArea' occurrence='2' text='Add' type='QPushButton' unnamed='1' visible='1'}")
+ activateItem(waitForObject("{type='QMenu' visible='1' unnamed='1'}"), "Custom Executable")
+ exePathChooser = waitForObject("{buddy={container=':Qt Creator.scrollArea_QScrollArea' text='Executable:' type='QLabel'} "
+ "type='Utils::PathChooser' unnamed='1' visible='1'}")
+ exeLineEd = getChildByClass(exePathChooser, "Utils::BaseValidatingLineEdit")
+ argLineEd = waitForObject("{buddy={container={type='QScrollArea' name='scrollArea'} "
+ "type='QLabel' text='Arguments:' visible='1'} type='QLineEdit' "
+ "unnamed='1' visible='1'}")
+ wdPathChooser = waitForObject("{buddy={container=':Qt Creator.scrollArea_QScrollArea' text='Working directory:' type='QLabel'} "
+ "type='Utils::PathChooser' unnamed='1' visible='1'}")
+ replaceEditorContent(exeLineEd, startAUT)
+ # the following is currently only configured for release builds (will be enhanced later)
+ if platform.system() in ('Microsoft', 'Windows'):
+ debOrRel = "release" + os.sep
+ else:
+ debOrRel = ""
+ replaceEditorContent(argLineEd, "--verbose --port=%d %s%s" % (port, debOrRel, projectName))
+ return True
+
+# function that retrieves a specific child object by its class
+# this is sometimes the best way to avoid using waitForObject() on objects that
+# occur more than once - but could easily be found by using a compound object
+# (e.g. search for Utils::PathChooser instead of Utils::BaseValidatingLineEdit and get the child)
+def getChildByClass(parent, classToSearchFor, occurence=1):
+ counter = 0
+ for child in object.children(parent):
+ if className(child) == classToSearchFor:
+ counter = counter + 1
+ if counter == occurence:
+ return child
+ return None
+
+# helper that tries to get the mkspec entry of the QtVersion ToolTip
+def __getMkspec__(qtToolTip):
+ return ___searchInsideQtVersionToolTip___(qtToolTip, "mkspec:")
+
+# helper that tries to get the qmake version entry of the QtVersion ToolTip
+def __getQMakeVersion__(qtToolTip):
+ return ___searchInsideQtVersionToolTip___(qtToolTip, "Version:")
+
+# helper that tries to get the path of the qmake libraries of the QtVersion ToolTip
+def __getQMakeLibPath__(qtToolTip):
+ qmake = ___searchInsideQtVersionToolTip___(qtToolTip, "qmake:")
+ result = getOutputFromCmdline("%s -v" % qmake)
+ for line in result.splitlines():
+ if "Using Qt version" in line:
+ return line.rsplit(" ", 1)[1]
+
+# helper that tries to get the path of qmake of the QtVersion ToolTip
+def __getQMakeBinPath__(qtToolTip):
+ qmake = ___searchInsideQtVersionToolTip___(qtToolTip, "qmake:")
+ endIndex = qmake.find("/qmake")
+ return qmake[:endIndex]
+
+# helper that does the work for __getMkspec__() and __getQMakeVersion__()
+def ___searchInsideQtVersionToolTip___(qtToolTip, what):
+ result = None
+ tmp = qtToolTip.split("<td>")
+ for i in range(len(tmp)):
+ if i % 2 == 0:
+ continue
+ if what in tmp[i]:
+ result = tmp[i + 1].split("</td>", 1)[0]
+ break
+ return result
+
+# get the Squish path that is needed to successfully hook into the compiled app
+def getSquishPath(mkspec, qmakev):
+ qmakev = ".".join(qmakev.split(".")[0:2])
+ path = None
+ mapfile = os.environ.get("QT_SQUISH_MAPFILE")
+ if mapfile and os.path.isfile(mapfile):
+ file = codecs.open(mapfile, "r", "utf-8")
+ pattern = re.compile("\s+")
+ for line in file:
+ if line[0] == "#":
+ continue
+ tmp = pattern.split(line, 2)
+ if tmp[0].strip("'\"") == qmakev and tmp[1].strip("'\"") == mkspec:
+ path = os.path.expanduser(tmp[2].strip().strip("'\""))
+ break
+ file.close()
+ else:
+ if not mapfile:
+ test.warning("Environment variable QT_SQUISH_MAPFILE isn't set. Using fallback test data.",
+ "See the README file how to use it.")
+ else:
+ test.warning("Environment variable QT_SQUISH_MAPFILE isn't set correctly or map file does not exist. Using fallback test data.",
+ "See the README file how to use it.")
+ # try the test data fallback
+ mapData = testData.dataset(os.getcwd() + "/../../shared_data/qt_squish_mapping.tsv")
+ for row, record in enumerate(mapData):
+ if testData.field(record, "qtversion") == qmakev and testData.field(record, "mkspec") == mkspec:
+ path = os.path.expanduser(testData.field(record, "path"))
+ break
+ return path
+
+# function to add a program to allow communication through the win firewall
+# param workingDir this directory is the parent of the project folder
+# param projectName this is the name of the project (the folder inside workingDir as well as the name for the executable)
+# param isReleaseBuild should currently always be set to True (will later add debug build testing)
+def allowAppThroughWinFW(workingDir, projectName, isReleaseBuild=True):
+ if not __isWinFirewallRunning__():
+ return
+ # WinFirewall seems to run - hopefully no other
+ result = __configureFW__(projectName, isReleaseBuild)
+ if result == 0:
+ test.log("Added %s to firewall" % projectName)
+ else:
+ test.fatal("Could not add %s as allowed program to win firewall" % projectName)
+
+# function to delete a (former added) program from the win firewall
+# param workingDir this directory is the parent of the project folder
+# param projectName this is the name of the project (the folder inside workingDir as well as the name for the executable)
+# param isReleaseBuild should currently always be set to True (will later add debug build testing)
+def deleteAppFromWinFW(workingDir, projectName, isReleaseBuild=True):
+ if not __isWinFirewallRunning__():
+ return
+ # WinFirewall seems to run - hopefully no other
+ result = __configureFW__(projectName, isReleaseBuild, False)
+ if result == 0:
+ test.log("Deleted %s from firewall" % projectName)
+ else:
+ test.fatal("Could not delete %s as allowed program from win firewall" % (mode, projectName))
+
+# helper that can modify the win firewall to allow a program to communicate through it or delete it
+# param addToFW defines whether to add (True) or delete (False) this programm to/from the firewall
+def __configureFW__(projectName, isReleaseBuild, addToFW=True):
+ if isReleaseBuild:
+ path = "%s%s%s%srelease%s%s" % (workingDir, os.sep, projectName, os.sep, os.sep, projectName)
+ else:
+ path = "%s%s%s%sdebug%s%s" % (workingDir, os.sep, projectName, os.sep, os.sep, projectName)
+ if addToFW:
+ mode = "add"
+ enable = "ENABLE"
+ else:
+ mode = "delete"
+ enable = ""
+ return subprocess.call('netsh firewall %s allowedprogram "%s.exe" %s %s' % (mode, path, projectName, enable))
+
+# helper to check whether win firewall is running or not
+# this doesn't check for other firewalls!
+def __isWinFirewallRunning__():
+ global fireWallState
+ if fireWallState != None:
+ return fireWallState
+ if not platform.system() in ('Microsoft' 'Windows'):
+ fireWallState = False
+ return False
+ result = getOutputFromCmdline("netsh firewall show state")
+ for line in result.splitlines():
+ if "Operational mode" in line:
+ fireWallState = not "Disable" in line
+ return fireWallState
+ return None
+
+# this function adds the given executable as an attachable AUT
+# Bad: executable/port could be empty strings - you should be aware of this
+def addExecutableAsAttachableAUT(executable, port, host=None):
+ if not __checkParamsForAttachableAUT__(executable, port):
+ return False
+ if host == None:
+ host = "localhost"
+ squishSrv = __getSquishServer__()
+ if (squishSrv == None):
+ return False
+ result = subprocess.call('%s --config addAttachableAUT "%s" %s:%s' % (squishSrv, executable, host, port), shell=True)
+ if result == 0:
+ test.passes("Added %s as attachable AUT" % executable)
+ else:
+ test.fail("Failed to add %s as attachable AUT" % executable)
+ return result == 0
+
+# this function removes the given executable as an attachable AUT
+# Bad: executable/port could be empty strings - you should be aware of this
+def removeExecutableAsAttachableAUT(executable, port, host=None):
+ if not __checkParamsForAttachableAUT__(executable, port):
+ return False
+ if host == None:
+ host = "localhost"
+ squishSrv = __getSquishServer__()
+ if (squishSrv == None):
+ return False
+ result = subprocess.call('%s --config removeAttachableAUT "%s" %s:%s' % (squishSrv, executable, host, port), shell=True)
+ if result == 0:
+ test.passes("Removed %s as attachable AUT" % executable)
+ else:
+ test.fail("Failed to remove %s as attachable AUT" % executable)
+ return result == 0
+
+def __checkParamsForAttachableAUT__(executable, port):
+ return port != None and executable != None
+
+def __getSquishServer__():
+ squishSrv = currentApplicationContext().environmentVariable("SQUISH_PREFIX")
+ if (squishSrv == ""):
+ test.fatal("SQUISH_PREFIX isn't set - leaving test")
+ return None
+ return os.path.abspath(squishSrv + "/bin/squishserver")
diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py
index dc620b245f..5594baa31b 100644
--- a/tests/system/shared/project.py
+++ b/tests/system/shared/project.py
@@ -77,7 +77,7 @@ def __createProjectSetNameAndPath__(path, projectName = None, checks = True):
# make sure this is not set as default location
ensureChecked("{type='QCheckBox' name='projectsDirectoryCheckBox' visible='1'}", False)
clickButton(waitForObject(":Next_QPushButton"))
- return projectName
+ return str(projectName)
def __createProjectHandleLastPage__(expectedFiles = None):
if expectedFiles != None:
@@ -156,6 +156,7 @@ def createNewQtQuickApplication(workingDir, projectName = None, templateFile = N
snooze(1)
clickButton(nextButton)
__createProjectHandleLastPage__()
+ return projectName
def createNewQtQuickUI(workingDir):
__createProjectSelectType__("Qt Quick Project", "Qt Quick UI")
diff --git a/tests/system/shared/project_explorer.py b/tests/system/shared/project_explorer.py
new file mode 100644
index 0000000000..79e6ec31f6
--- /dev/null
+++ b/tests/system/shared/project_explorer.py
@@ -0,0 +1,128 @@
+import re;
+
+# this class holds some constants for easier usage inside the Projects view
+class ProjectSettings:
+ BUILD = 1
+ RUN = 2
+
+# this class defines some constants for the views of the creator's MainWindow
+class ViewConstants:
+ WELCOME = 0
+ EDIT = 1
+ DESIGN = 2
+ DEBUG = 3
+ PROJECTS = 4
+ ANALYZE = 5
+ HELP = 6
+ # always adjust the following to the highest value of the available ViewConstants when adding new
+ LAST_AVAILABLE = HELP
+
+ # this function returns a regex of the tooltip of the FancyTabBar elements
+ # this is needed because the keyboard shortcut is OS specific
+ # if the provided argument does not match any of the ViewConstants it returns None
+ @staticmethod
+ def getToolTipForViewTab(viewTab):
+ if viewTab == ViewConstants.WELCOME:
+ return ur'Switch to <b>Welcome</b> mode <span style="color: gray; font-size: small">(Ctrl\+|\u2303)1</span>'
+ elif viewTab == ViewConstants.EDIT:
+ return ur'Switch to <b>Edit</b> mode <span style="color: gray; font-size: small">(Ctrl\+|\u2303)2</span>'
+ elif viewTab == ViewConstants.DESIGN:
+ return ur'Switch to <b>Design</b> mode <span style="color: gray; font-size: small">(Ctrl\+|\u2303)3</span>'
+ elif viewTab == ViewConstants.DEBUG:
+ return ur'Switch to <b>Debug</b> mode <span style="color: gray; font-size: small">(Ctrl\+|\u2303)4</span>'
+ elif viewTab == ViewConstants.PROJECTS:
+ return ur'Switch to <b>Projects</b> mode <span style="color: gray; font-size: small">(Ctrl\+|\u2303)5</span>'
+ elif viewTab == ViewConstants.ANALYZE:
+ return ur'Switch to <b>Analyze</b> mode <span style="color: gray; font-size: small">(Ctrl\+|\u2303)6</span>'
+ elif viewTab == ViewConstants.HELP:
+ return ur'Switch to <b>Help</b> mode <span style="color: gray; font-size: small">(Ctrl\+|\u2303)7</span>'
+ else:
+ return None
+
+# this function switches the MainWindow of creator to the specified view
+def switchViewTo(view):
+ if view < ViewConstants.WELCOME or view > ViewConstants.LAST_AVAILABLE:
+ return
+ tabBar = waitForObject("{type='Core::Internal::FancyTabBar' unnamed='1' visible='1' "
+ "window=':Qt Creator_Core::Internal::MainWindow'}")
+ mouseMove(tabBar, 10, 10 + 52 * view)
+ snooze(2)
+ text = str(QToolTip.text())
+ pattern = ViewConstants.getToolTipForViewTab(view)
+ if re.match(pattern, unicode(text), re.UNICODE):
+ test.passes("ToolTip verified")
+ else:
+ test.warning("ToolTip does not match", "Expected pattern: %s\nGot: %s" % (pattern, text))
+ mouseClick(waitForObject("{type='Core::Internal::FancyTabBar' unnamed='1' visible='1' "
+ "window=':Qt Creator_Core::Internal::MainWindow'}"), 5, 5 + 52 * view, 0, Qt.LeftButton)
+
+# this function is used to make sure that simple building prerequisites are met
+# param targetCount specifies how many build targets had been selected (it's important that this one is correct)
+# param currentTarget specifies which target should be selected for the next build (zero based index)
+# param setReleaseBuild defines whether the current target(s) will be set to a Release or a Debug build
+# param disableShadowBuild defines whether to disable shadow build or leave it unchanged (no matter what is defined)
+# param setForAll defines whether to set Release or Debug and ShadowBuild option for all targets or only for the currentTarget
+def prepareBuildSettings(targetCount, currentTarget, setReleaseBuild=True, disableShadowBuild=True, setForAll=True):
+ switchViewTo(ViewConstants.PROJECTS)
+ success = True
+ for current in range(targetCount):
+ if setForAll or current == currentTarget:
+ switchToBuildOrRunSettingsFor(targetCount, current, ProjectSettings.BUILD)
+ qtCombo = waitForObject(":scrollArea.qtVersionComboBox_QComboBox")
+ chooseThis = None
+ wait = False
+ try:
+ if qtCombo.currentText != defaultQtVersion:
+ selectFromCombo(":scrollArea.qtVersionComboBox_QComboBox", defaultQtVersion.replace(".", "\\."))
+ if setReleaseBuild:
+ chooseThis = "%s Release" % defaultQtVersion
+ else:
+ chooseThis = "%s Debug" % defaultQtVersion
+ editBuildCfg = waitForObject("{container={type='QScrollArea' name='scrollArea'} "
+ "leftWidget={container={type='QScrollArea' name='scrollArea'} "
+ "text='Edit build configuration:' type='QLabel'}"
+ "unnamed='1' type='QComboBox' visible='1'}", 20000)
+ if editBuildCfg.currentText != chooseThis:
+ wait = True
+ clickItem(editBuildCfg, chooseThis.replace(".", "\\."), 5, 5, 0, Qt.LeftButton)
+ else:
+ wait = False
+ except:
+ if current == currentTarget:
+ success = False
+ if wait and chooseThis != None:
+ waitFor("editBuildCfg.currentText==chooseThis")
+ ensureChecked("{name='shadowBuildCheckBox' type='QCheckBox' visible='1'}", not disableShadowBuild)
+ # get back to the current target
+ if currentTarget < 0 or currentTarget >= targetCount:
+ test.warning("Parameter currentTarget is out of range - will be ignored this time!")
+ else:
+ switchToBuildOrRunSettingsFor(targetCount, currentTarget, ProjectSettings.BUILD)
+ switchViewTo(ViewConstants.EDIT)
+ return success
+
+# this function switches to the build or the run settings (inside the Projects view)
+# if you haven't already switched to the Projects view this will fail and return False
+# param currentTarget specifies the target for which to switch into the specified settings (zero based index)
+# param targetCount specifies the number of targets currently defined (must be correct!)
+# param projectSettings specifies where to switch to (must be one of ProjectSettings.BUILD or ProjectSettings.RUN)
+def switchToBuildOrRunSettingsFor(targetCount, currentTarget, projectSettings):
+ try:
+ targetSel = waitForObject("{type='ProjectExplorer::Internal::TargetSelector' unnamed='1' "
+ "visible='1' window=':Qt Creator_Core::Internal::MainWindow'}")
+ except LookupError:
+ test.fatal("Wrong (time of) call - must be already at Projects view")
+ return False
+ ADD_BUTTON_WIDTH = 27 # bad... (taken from source)
+ selectorWidth = (targetSel.width - 3 - 2 * (ADD_BUTTON_WIDTH + 1)) / targetCount - 1
+ yToClick = targetSel.height * 3 / 5 + 5
+ if projectSettings == ProjectSettings.RUN:
+ xToClick = ADD_BUTTON_WIDTH + (selectorWidth + 1) * currentTarget - 2 + selectorWidth / 2 + 5
+ elif projectSettings == ProjectSettings.BUILD:
+ xToClick = ADD_BUTTON_WIDTH + (selectorWidth + 1) * currentTarget - 2 + selectorWidth / 2 - 5
+ else:
+ test.fatal("Don't know what you're trying to switch to")
+ return False
+ mouseClick(targetSel, xToClick, yToClick, 0, Qt.LeftButton)
+ return True
+
diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py
index 2aacbf68c1..4e13f34970 100644
--- a/tests/system/shared/qtcreator.py
+++ b/tests/system/shared/qtcreator.py
@@ -18,6 +18,8 @@ source("../../shared/build_utils.py")
source("../../shared/qtquick.py")
source("../../shared/project.py")
source("../../shared/editor_utils.py")
+source("../../shared/project_explorer.py")
+source("../../shared/hook_utils.py")
def waitForCleanShutdown(timeOut=10):
appCtxt = currentApplicationContext()
diff --git a/tests/system/shared/qtquick.py b/tests/system/shared/qtquick.py
index a8d6dd3c85..6a0bf8cb41 100644
--- a/tests/system/shared/qtquick.py
+++ b/tests/system/shared/qtquick.py
@@ -83,7 +83,7 @@ def __chooseTargets__(targets=QtQuickConstants.Targets.DESKTOP):
if mustCheck:
test.fail("Failed to check target '%s'" % QtQuickConstants.getStringForTarget(current))
-def runAndCloseApp():
+def runAndCloseApp(withHookInto=False, executable=None, port=None):
global processStarted, processExited
processStarted = processExited = False
installLazySignalHandler("{type='ProjectExplorer::ApplicationLaucher'}", "processStarted()", "__handleProcessStarted__")
@@ -101,13 +101,32 @@ def runAndCloseApp():
test.fatal("Couldn't start application - leaving test")
invokeMenuItem("File", "Exit")
return False
- # the following is currently a work-around for not using hooking into subprocesses
+ if withHookInto and not executable in ("", None):
+ __closeSubprocessByHookingIntoQmlApplicationViewer__(executable, port)
+ else:
+ __closeSubprocessByPushingStop__()
+ return True
+
+def __closeSubprocessByPushingStop__():
ensureChecked(":Qt Creator_Core::Internal::OutputPaneToggleButton")
playButton = verifyEnabled(":Qt Creator.ReRun_QToolButton", False)
stopButton = verifyEnabled(":Qt Creator.Stop_QToolButton")
clickButton(stopButton)
test.verify(playButton.enabled)
test.compare(stopButton.enabled, False)
+
+def __closeSubprocessByHookingIntoQmlApplicationViewer__(executable, port):
+ global processExited
+ ensureChecked(":Qt Creator_Core::Internal::OutputPaneToggleButton")
+ output = waitForObject("{type='Core::OutputWindow' visible='1' windowTitle='Application Output Window'}", 20000)
+ if port == None:
+ test.warning("I need a port number or attaching might fail.")
+ else:
+ waitFor("'Listening on port %d for incoming connectionsdone' in str(output.plainText)" % port, 5000)
+ attachToApplication(executable)
+ sendEvent("QCloseEvent", "{type='QmlApplicationViewer' unnamed='1' visible='1'}")
+ waitFor("processExited==True", 10000)
+ setApplicationContext(applicationContext("qtcreator"))
return True
def runAndCloseQtQuickUI():
diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py
index d42db116b6..a3ca6f6bb4 100644
--- a/tests/system/shared/utils.py
+++ b/tests/system/shared/utils.py
@@ -24,6 +24,12 @@ def ensureChecked(objectName, shouldBeChecked = True):
object = waitForObject(objectName, 20000)
if object.checked ^ shouldBeChecked:
clickButton(object)
+ if shouldBeChecked:
+ state = "checked"
+ else:
+ state = "unchecked"
+ test.log("New state for QCheckBox: %s" % state)
+ test.verify(object.checked == shouldBeChecked)
return object
def verifyEnabled(objectName, expectedState = True):
@@ -151,3 +157,10 @@ def logApplicationOutput():
"window=':Qt Creator_Core::Internal::MainWindow' occurrence='3'}")
output = waitForObject("{type='Core::OutputWindow' visible='1' windowTitle='Application Output Window'}", 20000)
test.log("Application Output:\n%s" % output.plainText)
+
+# get the output from a given cmdline call
+def getOutputFromCmdline(cmdline):
+ versCall = subprocess.Popen(cmdline, stdout=subprocess.PIPE, shell=True)
+ result = versCall.communicate()[0]
+ versCall.stdout.close()
+ return result
diff --git a/tests/system/shared_data/qt_squish_mapping.tsv b/tests/system/shared_data/qt_squish_mapping.tsv
new file mode 100644
index 0000000000..50d787cf4c
--- /dev/null
+++ b/tests/system/shared_data/qt_squish_mapping.tsv
@@ -0,0 +1,11 @@
+"qtversion" "mkspec" "path"
+"4.7" "win32-g++" "C:\QtSDK\src\creator-test-data\Squish_MinGW"
+"4.7" "win32-msvc2008" "C:\QtSDK\src\creator-test-data\Squish_MSVC9"
+"4.7" "win32-msvc-2010" "C:\QtSDK\src\creator-test-data\Squish_MSVC10"
+"4.7" "linux-g++" "~/QtSDK/src/creator-test-data/Squish_47x"
+"4.7" "macx-g++" "~/QtSDK/src/creator-test-data/Squish_47x"
+"4.8" "win32-g++" "C:\QtSDK\src\creator-test-data\Squish_MinGW"
+"4.8" "win32-msvc2008" "C:\QtSDK\src\creator-test-data\Squish_MSVC9"
+"4.8" "win32-msvc-2010" "C:\QtSDK\src\creator-test-data\Squish_MSVC10"
+"4.8" "linux-g++" "~/QtSDK/src/creator-test-data/Squish_47x"
+"4.8" "macx-g++" "~/QtSDK/src/creator-test-data/Squish_47x"
diff --git a/tests/system/suite_qtquick/tst_qtquick_creation/test.py b/tests/system/suite_qtquick/tst_qtquick_creation/test.py
index 113c59d246..ed2a15cef2 100644
--- a/tests/system/suite_qtquick/tst_qtquick_creation/test.py
+++ b/tests/system/suite_qtquick/tst_qtquick_creation/test.py
@@ -7,25 +7,38 @@ def main():
startApplication("qtcreator" + SettingsPath)
# using a temporary directory won't mess up an eventually exisiting
workingDir = tempDir()
- createNewQtQuickApplication(workingDir)
+ projectName = createNewQtQuickApplication(workingDir, targets = QtQuickConstants.Targets.DESKTOP)
# wait for parsing to complete
waitForSignal("{type='CppTools::Internal::CppModelManager' unnamed='1'}", "sourceFilesRefreshed(QStringList)", 30000)
test.log("Building project")
- invokeMenuItem("Build","Build All")
+ result = modifyRunSettingsForHookInto(projectName, 11223)
+ invokeMenuItem("Build", "Build All")
waitForSignal("{type='ProjectExplorer::BuildManager' unnamed='1'}", "buildQueueFinished(bool)", 300000)
if not checkCompile():
test.fatal("Compile failed")
else:
checkLastBuild()
test.log("Running project (includes build)")
- if runAndCloseApp():
+ if result:
+ result = addExecutableAsAttachableAUT(projectName, 11223)
+ allowAppThroughWinFW(workingDir, projectName)
+ if result:
+ result = runAndCloseApp(True, projectName, 11223)
+ else:
+ result = runAndCloseApp()
+ removeExecutableAsAttachableAUT(projectName, 11223)
+ deleteAppFromWinFW(workingDir, projectName)
+ else:
+ result = runAndCloseApp()
+ if result:
logApplicationOutput()
+
invokeMenuItem("File", "Exit")
def cleanup():
global workingDir
# waiting for a clean exit - for a full-remove of the temp directory
waitForCleanShutdown()
- if workingDir!=None:
+ if workingDir != None:
deleteDirIfExists(workingDir)