= 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 245d149064d..dfc6fd961fa 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 00000000000..300f5b8d634
--- /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 Build Environment' 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("| ")
+ for i in range(len(tmp)):
+ if i % 2 == 0:
+ continue
+ if what in tmp[i]:
+ result = tmp[i + 1].split(" | ", 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 dc620b245f3..5594baa31b7 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 00000000000..6ab2c547387
--- /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 Welcome mode (Ctrl\+|\u2303)1'
+ elif viewTab == ViewConstants.EDIT:
+ return ur'Switch to Edit mode (Ctrl\+|\u2303)2'
+ elif viewTab == ViewConstants.DESIGN:
+ return ur'Switch to Design mode (Ctrl\+|\u2303)3'
+ elif viewTab == ViewConstants.DEBUG:
+ return ur'Switch to Debug mode (Ctrl\+|\u2303)4'
+ elif viewTab == ViewConstants.PROJECTS:
+ return ur'Switch to Projects mode (Ctrl\+|\u2303)5'
+ elif viewTab == ViewConstants.ANALYZE:
+ return ur'Switch to Analyze mode (Ctrl\+|\u2303)6'
+ elif viewTab == ViewConstants.HELP:
+ return ur'Switch to Help mode (Ctrl\+|\u2303)7'
+ 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(qtCombo, 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 2aacbf68c15..4e13f34970e 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 a8d6dd3c85b..6a0bf8cb413 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 d42db116b6b..9ed8b5f19e4 100644
--- a/tests/system/shared/utils.py
+++ b/tests/system/shared/utils.py
@@ -24,16 +24,36 @@ 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):
- waitFor("object.exists('" + objectName + "')", 20000)
- object = findObject(objectName)
- test.compare(object.enabled, expectedState)
- return object
+# verify that an object is in an expected enable state. Returns the object.
+# param objectSpec specifies the object to check. It can either be a string determining an object
+# or the object itself. If it is an object, it must exist already.
+# param expectedState is the expected enable state of the object
+def verifyEnabled(objectSpec, expectedState = True):
+ if isinstance(objectSpec, (str, unicode)):
+ waitFor("object.exists('" + objectSpec + "')", 20000)
+ foundObject = findObject(objectSpec)
+ else:
+ foundObject = objectSpec
+ if objectSpec == None:
+ test.warning("No valid object in function verifyEnabled.")
+ else:
+ test.compare(foundObject.enabled, expectedState)
+ return foundObject
-def selectFromCombo(objectName, itemName):
- object = verifyEnabled(objectName)
+# select an item from a combo box
+# param objectSpec specifies the combo box. It can either be a string determining an object
+# or the object itself. If it is an object, it must exist already.
+# param itemName is the item to be selected in the combo box
+def selectFromCombo(objectSpec, itemName):
+ object = verifyEnabled(objectSpec)
mouseClick(object, 5, 5, 0, Qt.LeftButton)
mouseClick(waitForObjectItem(object, itemName), 5, 5, 0, Qt.LeftButton)
@@ -151,3 +171,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 00000000000..f62bfaaa058
--- /dev/null
+++ b/tests/system/shared_data/qt_squish_mapping.tsv
@@ -0,0 +1,13 @@
+"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_32"
+"4.7" "linux-g++-64" "~/QtSDK/src/creator-test-data/Squish_64"
+"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_32"
+"4.8" "linux-g++-64" "~/QtSDK/src/creator-test-data/Squish_64"
+"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 113c59d2464..ed2a15cef27 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)