Files
qt-creator/tests/system/suite_general/tst_default_settings/test.py
Christian Stenger e8727fcae2 Squish: Clean up single (left) mouse clicks on items or objects
Do no more use pixels as offset if we can handle this without.
Clicking on items by using an (x, y) offset will likely fail if
running on a machine with a different DPI setting.

Change-Id: I0e5a4985104bd1d68aadf8c5534583fa1b048edb
Reviewed-by: Robert Loehning <robert.loehning@qt.io>
2019-07-25 12:06:05 +00:00

395 lines
18 KiB
Python

############################################################################
#
# 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.
#
############################################################################
source("../../shared/qtcreator.py")
currentSelectedTreeItem = None
warningOrError = re.compile('<p><b>((Error|Warning).*?)</p>')
def main():
global appContext
emptySettings = tempDir()
__createMinimumIni__(emptySettings)
appContext = startQC(['-settingspath', '"%s"' % emptySettings], False)
if not startedWithoutPluginError():
return
invokeMenuItem("Tools", "Options...")
__checkKits__()
clickButton(waitForObject(":Options.Cancel_QPushButton"))
invokeMenuItem("File", "Exit")
__checkCreatedSettings__(emptySettings)
def __createMinimumIni__(emptyParent):
qtProjDir = os.path.join(emptyParent, "QtProject")
os.mkdir(qtProjDir)
iniFile = open(os.path.join(qtProjDir, "QtCreator.ini"), "w")
iniFile.write("[%General]\n")
iniFile.write("OverrideLanguage=C\n")
iniFile.close()
def __checkKits__():
mouseClick(waitForObjectItem(":Options_QListView", "Kits"))
# check compilers
expectedCompilers = __getExpectedCompilers__()
foundCompilers = []
foundCompilerNames = []
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Compilers")
__iterateTree__(":BuildAndRun_QTreeView", __compFunc__, foundCompilers, foundCompilerNames)
test.verify(__compareCompilers__(foundCompilers, expectedCompilers),
"Verifying found and expected compilers are equal.")
# check debugger
expectedDebuggers = __getExpectedDebuggers__()
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Debuggers")
foundDebugger = []
__iterateTree__(":BuildAndRun_QTreeView", __dbgFunc__, foundDebugger)
test.verify(__compareDebuggers__(foundDebugger, expectedDebuggers),
"Verifying found and expected debuggers are equal.")
# check Qt versions
qmakePath = which("qmake")
foundQt = []
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Qt Versions")
__iterateTree__(":qtdirList_QTreeView", __qtFunc__, foundQt, qmakePath)
test.verify(not qmakePath or len(foundQt) == 1,
"Was qmake from %s autodetected? Found %s" % (qmakePath, foundQt))
if foundQt:
foundQt = foundQt[0] # qmake from "which" should be used in kits
# check kits
clickOnTab(":Options.qt_tabwidget_tabbar_QTabBar", "Kits")
__iterateTree__(":BuildAndRun_QTreeView", __kitFunc__, foundQt, foundCompilerNames)
def __processSubItems__(treeObjStr, section, parModelIndexStr, doneItems,
additionalFunc, *additionalParameters):
global currentSelectedTreeItem
tree = waitForObject(treeObjStr)
model = tree.model()
items = dumpIndices(model, section)
for it in items:
indexName = str(it.data().toString())
itObj = "%s container=%s}" % (objectMap.realName(it)[:-1], parModelIndexStr)
alreadyDone = doneItems.count(itObj)
doneItems.append(itObj)
if alreadyDone:
itObj = "%s occurrence='%d'}" % (itObj[:-1], alreadyDone + 1)
currentSelectedTreeItem = waitForObject(itObj, 3000)
tree.scrollTo(it)
mouseClick(currentSelectedTreeItem)
additionalFunc(indexName, *additionalParameters)
currentSelectedTreeItem = None
if model.rowCount(it) > 0:
__processSubItems__(treeObjStr, it, itObj, doneItems,
additionalFunc, *additionalParameters)
def __iterateTree__(treeObjStr, additionalFunc, *additionalParameters):
global currentSelectedTreeItem
model = waitForObject(treeObjStr).model()
# 1st row: Auto-detected, 2nd row: Manual
for sect in dumpIndices(model):
doneItems = []
parentModelIndex = "%s container='%s'}" % (objectMap.realName(sect)[:-1], treeObjStr)
__processSubItems__(treeObjStr, sect, parentModelIndex, doneItems,
additionalFunc, *additionalParameters)
def __compFunc__(it, foundComp, foundCompNames):
# skip sub section items (will continue on its children)
if str(it) == "C" or str(it) == "C++":
return
try:
waitFor("object.exists(':Path.Utils_BaseValidatingLineEdit')", 1000)
pathLineEdit = findObject(":Path.Utils_BaseValidatingLineEdit")
foundComp.append(str(pathLineEdit.text))
except:
varsBatCombo = waitForObjectExists("{name='varsBatCombo' type='QComboBox' visible='1'}")
foundComp.append({it:str(varsBatCombo.currentText)})
foundCompNames.append(it)
def __dbgFunc__(it, foundDbg):
waitFor("object.exists(':Path.Utils_BaseValidatingLineEdit')", 2000)
pathLineEdit = findObject(":Path.Utils_BaseValidatingLineEdit")
foundDbg.append(str(pathLineEdit.text))
def __qtFunc__(it, foundQt, qmakePath):
qtPath = str(waitForObject(":QtSupport__Internal__QtVersionManager.qmake_QLabel").text)
if platform.system() in ('Microsoft', 'Windows'):
qtPath = qtPath.lower()
qmakePath = qmakePath.lower()
test.verify(os.path.isfile(qtPath) and os.access(qtPath, os.X_OK),
"Verifying found Qt (%s) is executable." % qtPath)
# Two Qt versions will be found when using qtchooser: QTCREATORBUG-14697
# Only add qmake from "which" to list
if qtPath == qmakePath:
foundQt.append(it)
try:
errorLabel = findObject(":QtSupport__Internal__QtVersionManager.errorLabel.QLabel")
test.warning("Detected error or warning: '%s'" % errorLabel.text)
except:
pass
def __kitFunc__(it, foundQt, foundCompNames):
global currentSelectedTreeItem, warningOrError
qtVersionStr = str(waitForObject(":Kits_QtVersion_QComboBox").currentText)
test.compare(it, "Desktop (default)", "Verifying whether default Desktop kit has been created.")
if foundQt:
test.compare(qtVersionStr, foundQt, "Verifying if Qt versions match.")
cCompilerCombo = findObject(":CCompiler:_QComboBox")
test.compare(cCompilerCombo.enabled, cCompilerCombo.count > 1,
"Verifying whether C compiler combo is enabled/disabled correctly.")
cppCompilerCombo = findObject(":CppCompiler:_QComboBox")
test.compare(cppCompilerCombo.enabled, cppCompilerCombo.count > 1,
"Verifying whether C++ compiler combo is enabled/disabled correctly.")
test.verify(str(cCompilerCombo.currentText) in foundCompNames,
"Verifying if one of the found C compilers had been set.")
test.verify(str(cppCompilerCombo.currentText) in foundCompNames,
"Verifying if one of the found C++ compilers had been set.")
if currentSelectedTreeItem:
foundWarningOrError = warningOrError.search(str(currentSelectedTreeItem.toolTip))
if foundWarningOrError:
details = str(foundWarningOrError.group(1)).replace("<br>", "\n")
details = details.replace("<b>", "").replace("</b>", "")
test.warning("Detected error and/or warning: %s" % details)
def __extendExpectedCompilersWithInternalClang__(expected):
global appContext
# QC ships a clang itself
regex = '^(.*(qtcreator(.exe)?|Qt Creator))( .*)?$' # QC with optional arguments
qcPath = re.match(regex, appContext.commandLine)
if qcPath is None:
test.warning("Regular expression failed.")
else:
qcPath = qcPath.group(1)
if platform.system() == 'Darwin':
internalClang = os.path.join(qcPath, '..', '..', 'Resources')
elif platform.system() in ('Windows', 'Microsoft'):
internalClang = os.path.join(qcPath, '..')
else:
internalClang = os.path.join(qcPath, '..', '..', 'libexec', 'qtcreator')
internalClang = os.path.join(internalClang, 'clang', 'bin', 'clang')
if platform.system() in ('Microsoft', 'Windows'):
internalClang += '-cl.exe'
internalClang = os.path.abspath(internalClang)
if os.path.exists(internalClang):
if platform.system() in ('Microsoft', 'Windows'):
# just add a fuzzy comparable name - everything else is not worth the effort here
expected.append({'^Default LLVM \d{2} bit based on MSVC\d{4}$':''})
else:
expected.append(internalClang)
else:
test.fail("QC package seems to be faulty - missing internal provided clang.\nIf this "
"is not a package, but a self-compiled QC, just copy the clang executable "
"located inside the LLVM_INSTALL_DIR/bin (used while building) to the "
"expected path.", "Expected '%s'" % internalClang)
def __getExpectedCompilers__():
# TODO: enhance this to distinguish between C and C++ compilers
expected = []
if platform.system() in ('Microsoft', 'Windows'):
expected.extend(__getWinCompilers__())
compilers = ["g++", "gcc"]
if platform.system() in ('Linux', 'Darwin'):
compilers.extend(["clang++", "clang", "afl-clang"])
compilers.extend(findAllFilesInPATH("clang-[0-9].[0-9]"))
compilers.extend(findAllFilesInPATH("*g++*"))
compilers.extend(findAllFilesInPATH("*gcc*"))
if platform.system() == 'Darwin':
for compilerExe in ('clang++', 'clang'):
xcodeClang = getOutputFromCmdline(["xcrun", "--find", compilerExe]).strip("\n")
if xcodeClang and os.path.exists(xcodeClang) and xcodeClang not in expected:
expected.append(xcodeClang)
__extendExpectedCompilersWithInternalClang__(expected)
for compiler in compilers:
compilerPath = which(compiler)
if compilerPath:
if compiler.endswith('clang++') or compiler.endswith('clang'):
if subprocess.call([compiler, '-dumpmachine']) != 0:
test.warning("clang found in PATH, but version is not supported.")
continue
expected.append(compilerPath)
return expected
def __getWinCompilers__():
result = []
for record in testData.dataset("win_compiler_paths.tsv"):
envvar = os.getenv(testData.field(record, "envvar"))
if not envvar:
continue
compiler = os.path.abspath(os.path.join(envvar, testData.field(record, "path"),
testData.field(record, "file")))
if os.path.exists(compiler):
parameters = testData.field(record, "displayedParameters").split(",")
usedParameters = testData.field(record, "usedParameters").split(",")
idePath = testData.field(record, "IDEPath")
if len(idePath):
if not os.path.exists(os.path.abspath(os.path.join(envvar, idePath))):
continue
if testData.field(record, "isSDK") == "true":
for para, used in zip(parameters, usedParameters):
result.append(
{"%s \(.*?\) \(%s\)" % (testData.field(record, 'displayName'),
para)
:"%s %s" % (compiler, used)})
else:
for para, used in zip(parameters, usedParameters):
result.append({"%s (%s)" % (testData.field(record, 'displayName'), para)
:"%s %s" % (compiler, used)})
return result
def __getExpectedDebuggers__():
exeSuffix = ""
result = []
if platform.system() in ('Microsoft', 'Windows'):
result.extend(__getCDB__())
exeSuffix = ".exe"
for debugger in ["gdb", "lldb"]:
result.extend(findAllFilesInPATH(debugger + exeSuffix))
if platform.system() == 'Linux':
result.extend(filter(lambda s: not ("lldb-platform" in s or "lldb-gdbserver" in s),
findAllFilesInPATH("lldb-*")))
if platform.system() == 'Darwin':
xcodeLLDB = getOutputFromCmdline(["xcrun", "--find", "lldb"]).strip("\n")
if xcodeLLDB and os.path.exists(xcodeLLDB) and xcodeLLDB not in result:
result.append(xcodeLLDB)
return result
def __getCDB__():
result = []
possibleLocations = ["C:\\Program Files\\Debugging Tools for Windows (x64)",
"C:\\Program Files (x86)\\Debugging Tools for Windows (x86)",
"C:\\Program Files (x86)\\Windows Kits\\8.0\\Debuggers\\x86",
"C:\\Program Files (x86)\\Windows Kits\\8.0\\Debuggers\\x64",
"C:\\Program Files\\Windows Kits\\8.0\\Debuggers\\x86",
"C:\\Program Files\\Windows Kits\\8.0\\Debuggers\\x64",
"C:\\Program Files (x86)\\Windows Kits\\8.1\\Debuggers\\x86",
"C:\\Program Files (x86)\\Windows Kits\\8.1\\Debuggers\\x64",
"C:\\Program Files\\Windows Kits\\8.1\\Debuggers\\x86",
"C:\\Program Files\\Windows Kits\\8.1\\Debuggers\\x64",
"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x86",
"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64"]
for cdbPath in possibleLocations:
cdb = os.path.join(cdbPath, "cdb.exe")
if os.path.exists(cdb):
result.append(cdb)
return result
def __compareCompilers__(foundCompilers, expectedCompilers):
# TODO: Check if all expected compilers were found
equal = True
flags = 0
isWin = platform.system() in ('Microsoft', 'Windows')
if isWin:
flags = re.IGNORECASE
for currentFound in foundCompilers:
if isinstance(currentFound, dict):
foundExp = False
for currentExp in expectedCompilers:
if isinstance(currentExp, (str, unicode)):
continue
key = currentExp.keys()[0]
# special case for (fuzzy) regex comparison on Windows (internal LLVM)
if isWin and key.startswith('^') and key.endswith('$'):
if re.match(key, currentFound.keys()[0], flags):
test.verify(os.path.exists(currentFound.values()[0].rsplit(" ", 1)[0]),
"Verifying whether shipped clang got set up.")
foundExp = True
break
# the regex .*? is used for the different possible version strings of the WinSDK
# if it's present a regex will be validated otherwise simple string comparison
if (((".*?" in key and re.match(key, currentFound.keys()[0], flags))
or currentFound.keys() == currentExp.keys())):
if ((isWin and os.path.abspath(currentFound.values()[0].lower())
== os.path.abspath(currentExp.values()[0].lower()))
or currentFound.values() == currentExp.values()):
foundExp = True
break
equal = foundExp
else:
if isWin:
equal = currentFound.lower() in __lowerStrs__(expectedCompilers)
else:
equal = currentFound in expectedCompilers
if not equal:
test.fail("Found '%s' but was not expected." % str(currentFound),
str(expectedCompilers))
break
return equal
def __compareDebuggers__(foundDebuggers, expectedDebuggers):
if not len(foundDebuggers) == len(expectedDebuggers):
test.log("Number of found and expected debuggers do not match.",
"Found: %s\nExpected: %s" % (str(foundDebuggers), str(expectedDebuggers)))
return False
if platform.system() in ('Microsoft', 'Windows'):
foundSet = set(__lowerStrs__(foundDebuggers))
expectedSet = set(__lowerStrs__(expectedDebuggers))
else:
foundSet = set(foundDebuggers)
expectedSet = set(expectedDebuggers)
return test.compare(foundSet, expectedSet,
"Verifying expected and found debuggers match.")
def __lowerStrs__(iterable):
for it in iterable:
if isinstance(it, (str, unicode)):
yield it.lower()
else:
yield it
def __checkCreatedSettings__(settingsFolder):
waitForCleanShutdown()
qtProj = os.path.join(settingsFolder, "QtProject")
folders = []
files = [{os.path.join(qtProj, "QtCreator.db"):0},
{os.path.join(qtProj, "QtCreator.ini"):30}]
folders.append(os.path.join(qtProj, "qtcreator"))
files.extend([{os.path.join(folders[0], "debuggers.xml"):0},
{os.path.join(folders[0], "devices.xml"):0},
{os.path.join(folders[0], "helpcollection.qhc"):0},
{os.path.join(folders[0], "profiles.xml"):0},
{os.path.join(folders[0], "qtversion.xml"):0},
{os.path.join(folders[0], "toolchains.xml"):0}])
folders.extend([os.path.join(folders[0], "generic-highlighter"),
os.path.join(folders[0], "macros")])
for f in folders:
test.verify(os.path.isdir(f),
"Verifying whether folder '%s' has been created." % os.path.basename(f))
for f in files:
fName = f.keys()[0]
fMinSize = f.values()[0]
text = "created non-empty"
if fMinSize > 0:
text = "modified"
test.verify(os.path.isfile(fName) and os.path.getsize(fName) > fMinSize,
"Verifying whether file '%s' has been %s." % (os.path.basename(fName), text))
def findAllFilesInPATH(programGlob):
result = []
for path in os.environ["PATH"].split(os.pathsep):
for curr in glob.glob(os.path.join(path, programGlob)):
if os.path.isfile(curr) and os.access(curr, os.X_OK):
result.append(curr)
return result