2016-01-15 14:55:33 +01:00
|
|
|
############################################################################
|
|
|
|
|
#
|
|
|
|
|
# Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
# Contact: https://www.qt.io/licensing/
|
|
|
|
|
#
|
|
|
|
|
# This file is part of Qt Creator.
|
|
|
|
|
#
|
|
|
|
|
# Commercial License Usage
|
|
|
|
|
# Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
# accordance with the commercial license agreement provided with the
|
|
|
|
|
# Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
# a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
# and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
# information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
|
#
|
|
|
|
|
# GNU General Public License Usage
|
|
|
|
|
# Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
# General Public License version 3 as published by the Free Software
|
|
|
|
|
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
# included in the packaging of this file. Please review the following
|
|
|
|
|
# information to ensure the GNU General Public License requirements will
|
|
|
|
|
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
|
#
|
|
|
|
|
############################################################################
|
2013-05-15 13:17:33 +02:00
|
|
|
|
2012-01-17 13:47:47 +01:00
|
|
|
import re;
|
|
|
|
|
|
2018-07-24 13:47:25 +02:00
|
|
|
def getBuildIssues():
|
|
|
|
|
ensureChecked(":Qt Creator_Issues_Core::Internal::OutputPaneToggleButton")
|
|
|
|
|
model = waitForObject(":Qt Creator.Issues_QListView").model()
|
|
|
|
|
return dumpBuildIssues(model)
|
|
|
|
|
|
2011-09-01 14:09:25 +02:00
|
|
|
# this method checks the last build (if there's one) and logs the number of errors, warnings and
|
2011-10-06 13:55:05 +02:00
|
|
|
# lines within the Issues output
|
2014-05-16 13:50:25 +02:00
|
|
|
# param expectedToFail can be used to tell this function if the build was expected to fail or not
|
|
|
|
|
# param createTasksFileOnError whether a tasks file should be created when building ends with errors
|
|
|
|
|
def checkLastBuild(expectedToFail=False, createTasksFileOnError=True):
|
2011-09-01 14:09:25 +02:00
|
|
|
try:
|
|
|
|
|
# can't use waitForObject() 'cause visible is always 0
|
2018-08-02 13:45:34 +02:00
|
|
|
findObject("{type='ProjectExplorer::Internal::BuildProgress' unnamed='1' }")
|
2011-09-01 14:09:25 +02:00
|
|
|
except LookupError:
|
|
|
|
|
test.log("checkLastBuild called without a build")
|
|
|
|
|
return
|
2018-07-24 13:47:25 +02:00
|
|
|
buildIssues = getBuildIssues()
|
2014-05-21 20:01:13 +02:00
|
|
|
types = map(lambda i: i[5], buildIssues)
|
|
|
|
|
errors = types.count("1")
|
|
|
|
|
warnings = types.count("2")
|
2013-04-17 10:54:14 +02:00
|
|
|
gotErrors = errors != 0
|
2016-04-06 17:46:39 +02:00
|
|
|
test.verify(not (gotErrors ^ expectedToFail), "Errors: %s | Warnings: %s" % (errors, warnings))
|
2011-09-01 14:09:25 +02:00
|
|
|
# additional stuff - could be removed... or improved :)
|
|
|
|
|
if gotErrors and createTasksFileOnError:
|
2013-04-17 10:54:14 +02:00
|
|
|
createTasksFile(buildIssues)
|
2011-09-01 14:09:25 +02:00
|
|
|
return not gotErrors
|
|
|
|
|
|
2011-09-05 11:00:32 +02:00
|
|
|
# helper function to check the compilation when build wasn't successful
|
|
|
|
|
def checkCompile():
|
2012-09-05 16:49:35 +02:00
|
|
|
ensureChecked(":Qt Creator_CompileOutput_Core::Internal::OutputPaneToggleButton")
|
2012-11-02 19:34:38 +01:00
|
|
|
output = waitForObject(":Qt Creator.Compile Output_Core::OutputWindow")
|
2011-09-05 11:00:32 +02:00
|
|
|
waitFor("len(str(output.plainText))>0",5000)
|
2013-02-04 11:08:38 +01:00
|
|
|
if compileSucceeded(output.plainText):
|
2012-01-10 16:55:57 +01:00
|
|
|
if os.getenv("SYSTEST_DEBUG") == "1":
|
|
|
|
|
test.log("Compile Output:\n%s" % output.plainText)
|
2013-02-04 11:08:38 +01:00
|
|
|
test.passes("Compile successful")
|
|
|
|
|
return True
|
2011-09-05 11:00:32 +02:00
|
|
|
else:
|
2011-10-06 16:46:03 +02:00
|
|
|
test.fail("Compile Output:\n%s" % output.plainText)
|
2013-02-04 11:08:38 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def compileSucceeded(compileOutput):
|
|
|
|
|
return None != re.match(".*exited normally\.\n\d\d:\d\d:\d\d: Elapsed time: "
|
|
|
|
|
"(\d:)?\d{2}:\d\d\.$", str(compileOutput), re.S)
|
2011-09-01 14:09:25 +02:00
|
|
|
|
2014-01-21 17:29:35 +01:00
|
|
|
def waitForCompile(timeout=60000):
|
2014-01-30 10:40:59 +01:00
|
|
|
progressBarWait(10000) # avoids switching to Issues pane after checking Compile Output
|
2014-01-21 17:29:35 +01:00
|
|
|
ensureChecked(":Qt Creator_CompileOutput_Core::Internal::OutputPaneToggleButton")
|
|
|
|
|
output = waitForObject(":Qt Creator.Compile Output_Core::OutputWindow")
|
|
|
|
|
if not waitFor("re.match('.*Elapsed time: (\d:)?\d{2}:\d\d\.$', str(output.plainText), re.S)", timeout):
|
|
|
|
|
test.warning("Waiting for compile timed out after %d s." % (timeout / 1000))
|
|
|
|
|
|
2013-04-17 10:54:14 +02:00
|
|
|
def dumpBuildIssues(listModel):
|
|
|
|
|
issueDump = []
|
2014-06-02 14:37:03 +02:00
|
|
|
for index in dumpIndices(listModel):
|
2013-04-17 10:54:14 +02:00
|
|
|
issueDump.extend([map(lambda role: index.data(role).toString(),
|
|
|
|
|
range(Qt.UserRole, Qt.UserRole + 6))])
|
|
|
|
|
return issueDump
|
|
|
|
|
|
2014-01-07 14:30:39 +01:00
|
|
|
# counter for written tasks files
|
|
|
|
|
tasksFileCount = 0
|
|
|
|
|
|
2013-04-17 10:54:14 +02:00
|
|
|
# helper method that writes a tasks file
|
|
|
|
|
def createTasksFile(buildIssues):
|
2014-01-07 14:30:39 +01:00
|
|
|
# currently used directory for tasks files
|
|
|
|
|
tasksFileDir = None
|
|
|
|
|
global tasksFileCount
|
2011-09-01 14:09:25 +02:00
|
|
|
if tasksFileDir == None:
|
2011-09-05 15:00:01 +02:00
|
|
|
tasksFileDir = os.getcwd() + "/tasks"
|
|
|
|
|
tasksFileDir = os.path.abspath(tasksFileDir)
|
|
|
|
|
if not os.path.exists(tasksFileDir):
|
|
|
|
|
try:
|
|
|
|
|
os.makedirs(tasksFileDir)
|
|
|
|
|
except OSError:
|
|
|
|
|
test.log("Could not create %s - falling back to a temporary directory" % tasksFileDir)
|
|
|
|
|
tasksFileDir = tempDir()
|
|
|
|
|
|
2011-09-01 14:09:25 +02:00
|
|
|
tasksFileCount += 1
|
|
|
|
|
outfile = os.path.join(tasksFileDir, os.path.basename(squishinfo.testCase)+"_%d.tasks" % tasksFileCount)
|
|
|
|
|
file = codecs.open(outfile, "w", "utf-8")
|
|
|
|
|
test.log("Writing tasks file - can take some time (according to number of issues)")
|
2013-04-17 10:54:14 +02:00
|
|
|
rows = len(buildIssues)
|
2012-02-03 14:19:01 +01:00
|
|
|
if os.environ.get("SYSTEST_DEBUG") == "1":
|
|
|
|
|
firstrow = 0
|
|
|
|
|
else:
|
|
|
|
|
firstrow = max(0, rows - 100)
|
2013-04-17 10:54:14 +02:00
|
|
|
for issue in buildIssues[firstrow:rows]:
|
2011-09-01 14:09:25 +02:00
|
|
|
# the following is currently a bad work-around
|
2013-04-17 10:54:14 +02:00
|
|
|
fData = issue[0] # file
|
|
|
|
|
lData = issue[1] # line -> linenumber or empty
|
|
|
|
|
tData = issue[5] # type -> 1==error 2==warning
|
|
|
|
|
dData = issue[3] # description
|
2011-09-01 14:09:25 +02:00
|
|
|
if lData == "":
|
|
|
|
|
lData = "-1"
|
|
|
|
|
if tData == "1":
|
|
|
|
|
tData = "error"
|
|
|
|
|
elif tData == "2":
|
|
|
|
|
tData = "warning"
|
|
|
|
|
else:
|
|
|
|
|
tData = "unknown"
|
2014-05-09 14:41:31 +02:00
|
|
|
if str(fData).strip() == "" and lData == "-1" and str(dData).strip() == "":
|
2014-05-05 11:10:50 +02:00
|
|
|
test.fatal("Found empty task.")
|
2011-09-01 14:09:25 +02:00
|
|
|
file.write("%s\t%s\t%s\t%s\n" % (fData, lData, tData, dData))
|
|
|
|
|
file.close()
|
|
|
|
|
test.log("Written tasks file %s" % outfile)
|
|
|
|
|
|
2018-08-02 11:26:43 +02:00
|
|
|
# returns a list of pairs each containing the ID of a kit (see class Targets)
|
2012-10-29 19:22:43 +01:00
|
|
|
# and the name of the matching build configuration
|
2012-01-17 13:47:47 +01:00
|
|
|
# param filter is a regular expression to filter the configuration by their name
|
2018-08-02 11:26:43 +02:00
|
|
|
def iterateBuildConfigs(filter = ""):
|
2012-01-17 13:47:47 +01:00
|
|
|
switchViewTo(ViewConstants.PROJECTS)
|
2012-10-29 19:22:43 +01:00
|
|
|
configs = []
|
2018-08-02 11:26:43 +02:00
|
|
|
for currentKit in iterateConfiguredKits():
|
|
|
|
|
switchToBuildOrRunSettingsFor(currentKit, ProjectSettings.BUILD)
|
2012-11-02 19:34:38 +01:00
|
|
|
model = waitForObject(":scrollArea.Edit build configuration:_QComboBox").model()
|
2012-10-29 19:22:43 +01:00
|
|
|
prog = re.compile(filter)
|
|
|
|
|
# for each row in the model, write its data to a list
|
|
|
|
|
configNames = dumpItems(model)
|
|
|
|
|
# pick only those configuration names which pass the filter
|
|
|
|
|
configs += zip([currentKit] * len(configNames),
|
|
|
|
|
[config for config in configNames if prog.match(config)])
|
2012-01-17 13:47:47 +01:00
|
|
|
switchViewTo(ViewConstants.EDIT)
|
|
|
|
|
return configs
|
|
|
|
|
|
|
|
|
|
# selects a build configuration for building the current project
|
2018-08-02 11:26:43 +02:00
|
|
|
# param wantedKit specifies the ID of the kit to select (see class Targets)
|
2012-01-17 13:47:47 +01:00
|
|
|
# param configName is the name of the configuration that should be selected
|
2014-05-15 11:39:33 +02:00
|
|
|
# param afterSwitchTo the ViewConstant of the mode to switch to after selecting or None
|
2018-08-02 11:26:43 +02:00
|
|
|
def selectBuildConfig(wantedKit, configName, afterSwitchTo=ViewConstants.EDIT):
|
2012-01-17 13:47:47 +01:00
|
|
|
switchViewTo(ViewConstants.PROJECTS)
|
2018-08-02 11:26:43 +02:00
|
|
|
if any((switchToBuildOrRunSettingsFor(wantedKit, ProjectSettings.BUILD),
|
|
|
|
|
selectFromCombo(":scrollArea.Edit build configuration:_QComboBox", configName))):
|
2014-06-03 14:06:58 +02:00
|
|
|
progressBarWait(30000)
|
2018-08-02 11:26:43 +02:00
|
|
|
if afterSwitchTo:
|
|
|
|
|
if ViewConstants.FIRST_AVAILABLE <= afterSwitchTo <= ViewConstants.LAST_AVAILABLE:
|
|
|
|
|
switchViewTo(afterSwitchTo)
|
|
|
|
|
else:
|
|
|
|
|
test.warning("Don't know where you trying to switch to (%s)" % afterSwitchTo)
|
2012-03-26 14:13:39 +02:00
|
|
|
|
2012-05-11 17:38:58 +02:00
|
|
|
# This will not trigger a rebuild. If needed, caller has to do this.
|
2018-08-02 11:26:43 +02:00
|
|
|
def verifyBuildConfig(currentTarget, configName, shouldBeDebug=False, enableShadowBuild=False, enableQmlDebug=False):
|
|
|
|
|
selectBuildConfig(currentTarget, configName, None)
|
2012-08-01 11:30:31 +02:00
|
|
|
ensureChecked(waitForObject(":scrollArea.Details_Utils::DetailsButton"))
|
2012-03-26 14:13:39 +02:00
|
|
|
ensureChecked("{name='shadowBuildCheckBox' type='QCheckBox' visible='1'}", enableShadowBuild)
|
|
|
|
|
buildCfCombo = waitForObject("{type='QComboBox' name='buildConfigurationComboBox' visible='1' "
|
2012-08-01 11:30:31 +02:00
|
|
|
"window=':Qt Creator_Core::Internal::MainWindow'}")
|
2012-03-26 14:13:39 +02:00
|
|
|
if shouldBeDebug:
|
|
|
|
|
test.compare(buildCfCombo.currentText, 'Debug', "Verifying whether it's a debug build")
|
|
|
|
|
else:
|
|
|
|
|
test.compare(buildCfCombo.currentText, 'Release', "Verifying whether it's a release build")
|
2013-08-22 16:25:33 +02:00
|
|
|
if enableQmlDebug:
|
|
|
|
|
try:
|
|
|
|
|
libLabel = waitForObject(":scrollArea.Library not available_QLabel", 2000)
|
|
|
|
|
mouseClick(libLabel, libLabel.width - 10, libLabel.height / 2, 0, Qt.LeftButton)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
# Since waitForObject waits for the object to be enabled,
|
|
|
|
|
# it will wait here until compilation of the debug libraries has finished.
|
|
|
|
|
qmlDebugCheckbox = waitForObject(":scrollArea.qmlDebuggingLibraryCheckBox_QCheckBox", 150000)
|
|
|
|
|
if qmlDebugCheckbox.checked != enableQmlDebug:
|
|
|
|
|
clickButton(qmlDebugCheckbox)
|
|
|
|
|
# Don't rebuild now
|
|
|
|
|
clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000))
|
|
|
|
|
try:
|
|
|
|
|
problemFound = waitForObject("{window=':Qt Creator_Core::Internal::MainWindow' "
|
|
|
|
|
"type='QLabel' name='problemLabel' visible='1'}", 1000)
|
|
|
|
|
if problemFound:
|
|
|
|
|
test.warning('%s' % problemFound.text)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
qmlDebugCheckbox = findObject(":scrollArea.qmlDebuggingLibraryCheckBox_QCheckBox")
|
|
|
|
|
if qmlDebugCheckbox.enabled and qmlDebugCheckbox.checked:
|
|
|
|
|
test.log("Qml debugging libraries are available - unchecking qml debugging.")
|
|
|
|
|
clickButton(qmlDebugCheckbox)
|
|
|
|
|
# Don't rebuild now
|
|
|
|
|
clickButton(waitForObject(":QML Debugging.No_QPushButton", 5000))
|
2012-08-01 11:30:31 +02:00
|
|
|
clickButton(waitForObject(":scrollArea.Details_Utils::DetailsButton"))
|
2012-03-26 14:13:39 +02:00
|
|
|
switchViewTo(ViewConstants.EDIT)
|
2013-07-23 13:42:10 +02:00
|
|
|
|
|
|
|
|
# verify if building and running of project was successful
|
|
|
|
|
def verifyBuildAndRun():
|
|
|
|
|
# check compile output if build successful
|
|
|
|
|
checkCompile()
|
|
|
|
|
# check application output log
|
|
|
|
|
appOutput = logApplicationOutput()
|
|
|
|
|
if appOutput:
|
2013-09-19 17:10:49 +02:00
|
|
|
test.verify((re.search(".* exited with code \d+", str(appOutput)) or
|
|
|
|
|
re.search("The program has unexpectedly finished\.", str(appOutput))) and
|
2013-07-23 13:42:10 +02:00
|
|
|
re.search('[Ss]tarting.*', str(appOutput)),
|
|
|
|
|
"Verifying if built app started and closed successfully.")
|
|
|
|
|
|
|
|
|
|
# run project for debug and release
|
2018-08-02 11:26:43 +02:00
|
|
|
def runVerify():
|
|
|
|
|
availableConfigs = iterateBuildConfigs()
|
2013-07-23 13:42:10 +02:00
|
|
|
if not availableConfigs:
|
|
|
|
|
test.fatal("Haven't found build configurations, quitting")
|
|
|
|
|
invokeMenuItem("File", "Save All")
|
|
|
|
|
invokeMenuItem("File", "Exit")
|
|
|
|
|
# select debug configuration
|
|
|
|
|
for kit, config in availableConfigs:
|
2018-08-02 11:26:43 +02:00
|
|
|
selectBuildConfig(kit, config)
|
2013-07-23 13:42:10 +02:00
|
|
|
test.log("Using build config '%s'" % config)
|
2014-01-23 16:29:05 +01:00
|
|
|
if runAndCloseApp() == None:
|
|
|
|
|
checkCompile()
|
|
|
|
|
continue
|
2013-07-23 13:42:10 +02:00
|
|
|
verifyBuildAndRun()
|
|
|
|
|
mouseClick(waitForObject(":*Qt Creator.Clear_QToolButton"))
|