forked from qt-creator/qt-creator
Qt Creator's support for Symbian was at its peak in version 2.4.x. Nobody really verified it in Qt Creator 2.5 or 2.6. It is most likely rotten. Let's remove it! Also, the Symbian support code was spread throughout the whole Qt Creator code base. The plugin interfaces evolved in the meantime and target platforms like Android or QNX have 99% of their code in separate plugins. In case anyone wants to revive Symbian support in Qt Creator, please create a plugin for it. Change-Id: I56a758a3e2fd5b8c64d9aeb8f63d8e916c4883be Reviewed-by: Alessandro Portale <alessandro.portale@nokia.com>
435 lines
19 KiB
Python
435 lines
19 KiB
Python
import tempfile
|
|
|
|
def neededFilePresent(path):
|
|
found = os.path.exists(path)
|
|
if os.getenv("SYSTEST_DEBUG") == "1":
|
|
checkAccess(path)
|
|
elif not found:
|
|
test.fatal("Missing file or directory: " + path)
|
|
return found
|
|
|
|
def tempDir():
|
|
Result = os.path.abspath(os.getcwd()+"/../../testing")
|
|
if not os.path.exists(Result):
|
|
os.mkdir(Result)
|
|
return tempfile.mkdtemp(prefix="qtcreator_", dir=Result)
|
|
|
|
def deleteDirIfExists(path):
|
|
shutil.rmtree(path, True)
|
|
|
|
def verifyChecked(objectName):
|
|
object = waitForObject(objectName, 20000)
|
|
test.compare(object.checked, True)
|
|
return object
|
|
|
|
def ensureChecked(objectName, shouldBeChecked = True, timeout=20000):
|
|
object = waitForObject(objectName, timeout)
|
|
if object.checked ^ shouldBeChecked:
|
|
clickButton(object)
|
|
if shouldBeChecked:
|
|
state = "checked"
|
|
else:
|
|
state = "unchecked"
|
|
test.log("New state for QCheckBox: %s" % state,
|
|
str(objectName))
|
|
test.verify(waitFor("object.checked == shouldBeChecked", 1000))
|
|
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
|
|
|
|
# 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
|
|
# returns True if selection was changed or False if the wanted value was already selected
|
|
def selectFromCombo(objectSpec, itemName):
|
|
object = verifyEnabled(objectSpec)
|
|
if itemName == str(object.currentText):
|
|
return False
|
|
else:
|
|
mouseClick(object, 5, 5, 0, Qt.LeftButton)
|
|
mouseClick(waitForObjectItem(object, itemName.replace(".", "\\.")), 5, 5, 0, Qt.LeftButton)
|
|
waitFor("str(object.currentText)==itemName", 5000)
|
|
return True
|
|
|
|
def selectFromLocator(filter, itemName = None):
|
|
if itemName == None:
|
|
itemName = filter
|
|
itemName = itemName.replace(".", "\\.").replace("_", "\\_")
|
|
locator = waitForObject(":*Qt Creator_Utils::FilterLineEdit", 20000)
|
|
mouseClick(locator, 5, 5, 0, Qt.LeftButton)
|
|
replaceEditorContent(locator, filter)
|
|
# clicking the wanted item
|
|
# if you replace this by pressing ENTER, be sure that something is selected
|
|
# otherwise you will run into unwanted behavior
|
|
wantedItem = waitForObjectItem("{type='QTreeView' unnamed='1' visible='1'}", itemName)
|
|
doubleClick(wantedItem, 5, 5, 0, Qt.LeftButton)
|
|
|
|
def wordUnderCursor(window):
|
|
cursor = window.textCursor()
|
|
oldposition = cursor.position()
|
|
cursor.movePosition(QTextCursor.StartOfWord)
|
|
cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
|
|
returnValue = cursor.selectedText()
|
|
cursor.setPosition(oldposition)
|
|
return returnValue
|
|
|
|
def lineUnderCursor(window):
|
|
cursor = window.textCursor()
|
|
oldposition = cursor.position()
|
|
cursor.movePosition(QTextCursor.StartOfLine)
|
|
cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
|
|
returnValue = cursor.selectedText()
|
|
cursor.setPosition(oldposition)
|
|
return returnValue
|
|
|
|
def which(program):
|
|
def is_exe(fpath):
|
|
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
|
|
|
|
def callableFile(path):
|
|
if is_exe(path):
|
|
return path
|
|
if platform.system() in ('Windows', 'Microsoft'):
|
|
for suffix in suffixes.split(os.pathsep):
|
|
if is_exe(path + suffix):
|
|
return path + suffix
|
|
return None
|
|
|
|
if platform.system() in ('Windows', 'Microsoft'):
|
|
suffixes = os.getenv("PATHEXT")
|
|
if not suffixes:
|
|
test.fatal("Can't read environment variable PATHEXT. Please check your installation.")
|
|
suffixes = ""
|
|
|
|
fpath, fname = os.path.split(program)
|
|
if fpath:
|
|
return callableFile(program)
|
|
else:
|
|
if platform.system() in ('Windows', 'Microsoft'):
|
|
cf = callableFile(os.getcwd() + os.sep + program)
|
|
if cf:
|
|
return cf
|
|
for path in os.environ["PATH"].split(os.pathsep):
|
|
exe_file = os.path.join(path, program)
|
|
cf = callableFile(exe_file)
|
|
if cf:
|
|
return cf
|
|
return None
|
|
|
|
signalObjects = {}
|
|
|
|
# do not call this function directly - it's only a helper
|
|
def __callbackFunction__(object, *args):
|
|
global signalObjects
|
|
# test.log("__callbackFunction__: "+objectMap.realName(object))
|
|
signalObjects[objectMap.realName(object)] += 1
|
|
|
|
def waitForSignal(object, signal, timeout=30000):
|
|
global signalObjects
|
|
realName = prepareForSignal(object, signal)
|
|
beforeCount = signalObjects[realName]
|
|
waitFor("signalObjects[realName] > beforeCount", timeout)
|
|
|
|
def prepareForSignal(object, signal):
|
|
global signalObjects
|
|
overrideInstallLazySignalHandler()
|
|
realName = objectMap.realName(object)
|
|
# test.log("waitForSignal: "+realName)
|
|
if not (realName in signalObjects):
|
|
signalObjects[realName] = 0
|
|
installLazySignalHandler(object, signal, "__callbackFunction__")
|
|
return realName
|
|
|
|
# this function removes the user files of given pro file(s)
|
|
# can be called with a single string object or a list of strings holding path(s) to
|
|
# the pro file(s) returns False if it could not remove all user files or has been
|
|
# called with an unsupported object
|
|
def cleanUpUserFiles(pathsToProFiles=None):
|
|
if pathsToProFiles==None:
|
|
return False
|
|
if isinstance(pathsToProFiles, (str, unicode)):
|
|
filelist = glob.glob(pathsToProFiles+".user*")
|
|
elif isinstance(pathsToProFiles, (list, tuple)):
|
|
filelist = []
|
|
for p in pathsToProFiles:
|
|
filelist.extend(glob.glob(p+".user*"))
|
|
else:
|
|
test.fatal("Got an unsupported object.")
|
|
return False
|
|
doneWithoutErrors = True
|
|
for file in filelist:
|
|
try:
|
|
file = os.path.abspath(file)
|
|
os.remove(file)
|
|
except:
|
|
doneWithoutErrors = False
|
|
return doneWithoutErrors
|
|
|
|
def invokeMenuItem(menu, item, subItem = None):
|
|
menuObject = waitForObjectItem(":Qt Creator.QtCreator.MenuBar_QMenuBar", menu)
|
|
waitFor("menuObject.visible", 1000)
|
|
activateItem(menuObject)
|
|
itemObject = waitForObjectItem(objectMap.realName(menuObject), item)
|
|
waitFor("itemObject.enabled", 2000)
|
|
activateItem(itemObject)
|
|
if subItem != None:
|
|
sub = itemObject.menu()
|
|
waitFor("sub.visible", 1000)
|
|
activateItem(waitForObjectItem(sub, subItem))
|
|
|
|
def logApplicationOutput():
|
|
# make sure application output is shown
|
|
ensureChecked("{type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' "
|
|
"window=':Qt Creator_Core::Internal::MainWindow' occurrence='3'}")
|
|
try:
|
|
output = waitForObject("{type='Core::OutputWindow' visible='1' windowTitle='Application Output Window'}", 20000)
|
|
test.log("Application Output:\n%s" % output.plainText)
|
|
return str(output.plainText)
|
|
except:
|
|
test.fail("Could not find any Application Output - did the project run?")
|
|
return None
|
|
|
|
# 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
|
|
|
|
def selectFromFileDialog(fileName):
|
|
if platform.system() == "Darwin":
|
|
snooze(1)
|
|
nativeType("<Command+Shift+g>")
|
|
snooze(1)
|
|
nativeType(fileName)
|
|
snooze(1)
|
|
nativeType("<Return>")
|
|
snooze(2)
|
|
nativeType("<Return>")
|
|
else:
|
|
fName = os.path.basename(os.path.abspath(fileName))
|
|
pName = os.path.dirname(os.path.abspath(fileName)) + os.sep
|
|
waitForObject("{name='QFileDialog' type='QFileDialog' visible='1'}")
|
|
pathLine = waitForObject("{name='fileNameEdit' type='QLineEdit' visible='1'}")
|
|
replaceEditorContent(pathLine, pName)
|
|
clickButton(findObject("{text='Open' type='QPushButton'}"))
|
|
waitFor("str(pathLine.text)==''")
|
|
replaceEditorContent(pathLine, fName)
|
|
clickButton(findObject("{text='Open' type='QPushButton'}"))
|
|
|
|
# add qt.qch from SDK path
|
|
def addHelpDocumentationFromSDK():
|
|
global sdkPath
|
|
invokeMenuItem("Tools", "Options...")
|
|
waitForObjectItem(":Options_QListView", "Help")
|
|
clickItem(":Options_QListView", "Help", 14, 15, 0, Qt.LeftButton)
|
|
waitForObject("{container=':Options.qt_tabwidget_tabbar_QTabBar' type='TabItem' text='Documentation'}")
|
|
clickTab(waitForObject(":Options.qt_tabwidget_tabbar_QTabBar"), "Documentation")
|
|
# get rid of all docs already registered
|
|
listWidget = waitForObject("{type='QListWidget' name='docsListWidget' visible='1'}")
|
|
for i in range(listWidget.count):
|
|
rect = listWidget.visualItemRect(listWidget.item(0))
|
|
mouseClick(listWidget, rect.x+5, rect.y+5, 0, Qt.LeftButton)
|
|
mouseClick(waitForObject("{type='QPushButton' name='removeButton' visible='1'}"), 5, 5, 0, Qt.LeftButton)
|
|
clickButton(waitForObject("{type='QPushButton' name='addButton' visible='1' text='Add...'}"))
|
|
selectFromFileDialog("%s/Documentation/qt.qch" % sdkPath)
|
|
clickButton(waitForObject(":Options.OK_QPushButton"))
|
|
|
|
def verifyOutput(string, substring, outputFrom, outputIn):
|
|
index = string.find(substring)
|
|
if (index == -1):
|
|
test.fail("Output from " + outputFrom + " could not be found in " + outputIn)
|
|
else:
|
|
test.passes("Output from " + outputFrom + " found at position " + str(index) + " of " + outputIn)
|
|
|
|
# function that verifies the existance and the read permissions
|
|
# of the given file path
|
|
# if the executing user hasn't the read permission it checks
|
|
# the parent folders for their execute permission
|
|
def checkAccess(pathToFile):
|
|
if os.path.exists(pathToFile):
|
|
test.log("Path '%s' exists" % pathToFile)
|
|
if os.access(pathToFile, os.R_OK):
|
|
test.log("Got read access on '%s'" % pathToFile)
|
|
else:
|
|
test.fail("No read permission on '%s'" % pathToFile)
|
|
else:
|
|
test.fatal("Path '%s' does not exist or cannot be accessed" % pathToFile)
|
|
__checkParentAccess__(pathToFile)
|
|
|
|
# helper function for checking the execute rights of all
|
|
# parents of filePath
|
|
def __checkParentAccess__(filePath):
|
|
for i in range(1, filePath.count(os.sep)):
|
|
tmp = filePath.rsplit(os.sep, i)[0]
|
|
if os.access(tmp, os.X_OK):
|
|
test.log("Got execute permission on '%s'" % tmp)
|
|
else:
|
|
test.fail("No execute permission on '%s'" % tmp)
|
|
|
|
# this function checks for all configured Qt versions inside
|
|
# options dialog and returns a dict holding the targets as keys
|
|
# and a list of supported versions as value
|
|
def getCorrectlyConfiguredTargets():
|
|
result = {}
|
|
for tv in iterateQtVersions():
|
|
for target,version in tv.iteritems():
|
|
# Dialog sometimes differs from targets' names
|
|
if target == "Maemo":
|
|
target = "Maemo5"
|
|
implicitTargets = [target]
|
|
if target == "Desktop" and platform.system() in ("Linux", "Darwin"):
|
|
implicitTargets.append("Embedded Linux")
|
|
for currentTarget in implicitTargets:
|
|
if currentTarget in result:
|
|
oldV = result[currentTarget]
|
|
if version not in oldV:
|
|
oldV.append(version)
|
|
result.update({currentTarget:oldV})
|
|
else:
|
|
result.update({currentTarget:[version]})
|
|
test.log("Correctly configured targets: %s" % str(result))
|
|
return result
|
|
|
|
def visibleCheckBoxExists(text):
|
|
try:
|
|
findObject("{type='QCheckBox' text='%s' visible='1'}" % text)
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
# this function verifies if the text matches the given
|
|
# regex inside expectedTexts
|
|
# param text must be a single str/unicode
|
|
# param expectedTexts can be str/unicode/list/tuple
|
|
def regexVerify(text, expectedTexts):
|
|
if isinstance(expectedTexts, (str,unicode)):
|
|
expectedTexts = [expectedTexts]
|
|
for curr in expectedTexts:
|
|
pattern = re.compile(curr)
|
|
if pattern.match(text):
|
|
return True
|
|
return False
|
|
|
|
def checkDebuggingLibrary(targVersion, targets):
|
|
# internal function to execute while iterating Qt versions
|
|
def __checkDebugLibsInternalFunc__(target, version, targVersion, targStrings):
|
|
built = failed = 0
|
|
container = ("container=':qt_tabwidget_stackedwidget.QtSupport__Internal__"
|
|
"QtVersionManager_QtSupport::Internal::QtOptionsPageWidget'")
|
|
buildLogWindow = ("window={name='QtSupport__Internal__ShowBuildLog' type='QDialog' "
|
|
"visible='1' windowTitle?='Debugging Helper Build Log*'}")
|
|
if target in targStrings and version == targVersion:
|
|
detailsButton = waitForObject("{%s type='Utils::DetailsButton' text='Details' "
|
|
"visible='1' unnamed='1' occurrence='2'}" % container)
|
|
ensureChecked(detailsButton)
|
|
gdbHelperStat = waitForObject("{%s type='QLabel' name='gdbHelperStatus' "
|
|
"visible='1'}" % container)
|
|
if 'Not yet built.' in str(gdbHelperStat.text):
|
|
clickButton(waitForObject("{%s type='QPushButton' name='gdbHelperBuildButton' "
|
|
"text='Build' visible='1'}" % container))
|
|
buildLog = waitForObject("{type='QPlainTextEdit' name='log' visible='1' %s}" % buildLogWindow)
|
|
if str(buildLog.plainText).endswith('Build succeeded.'):
|
|
built += 1
|
|
else:
|
|
failed += 1
|
|
test.fail("Building GDB Helper failed",
|
|
buildLog.plainText)
|
|
clickButton(waitForObject("{type='QPushButton' text='Close' unnamed='1' "
|
|
"visible='1' %s}" % buildLogWindow))
|
|
else:
|
|
built += 1
|
|
ensureChecked(detailsButton, False)
|
|
return (built, failed)
|
|
# end of internal function
|
|
|
|
tv, builtAndFailedList = iterateQtVersions(False, __checkDebugLibsInternalFunc__, targVersion,
|
|
QtQuickConstants.getTargetsAsStrings(targets))
|
|
built = failed = 0
|
|
for current in builtAndFailedList:
|
|
if current[0]:
|
|
built += current[0]
|
|
if current[1]:
|
|
failed += current[1]
|
|
if failed > 0:
|
|
test.fail("%d of %d GDB Helper compilations failed." % (failed, failed+built))
|
|
else:
|
|
test.passes("%d GDB Helper found compiled or successfully built." % built)
|
|
return failed == 0
|
|
|
|
# function that opens Options Dialog and parses the configured Qt versions
|
|
# param keepOptionsOpen set to True if the Options dialog should stay open when
|
|
# leaving this function
|
|
# param additionalFunction pass a function or name of a defined function to execute
|
|
# for each correctly configured item on the list of Qt versions
|
|
# (Qt versions having no assigned toolchain, failing qmake,... will be skipped)
|
|
# this function must take at least 2 parameters - the first is the target name
|
|
# and the second the version of the current selected Qt version item
|
|
# param argsForAdditionalFunc you can specify as much parameters as you want to pass
|
|
# to additionalFunction from the outside
|
|
# the function returns a list of dict holding target-version mappings if used without
|
|
# additionalFunction
|
|
# WATCH OUT! if you're using the additionalFunction parameter - this function will
|
|
# return the list mentioned above as well as the returned value(s) from
|
|
# additionalFunction. You MUST call this function like
|
|
# result, additionalResult = _iterateQtVersions(...)
|
|
# where additionalResult is the result of all executions of additionalFunction which
|
|
# means it is a list of results.
|
|
def iterateQtVersions(keepOptionsOpen=False, additionalFunction=None, *argsForAdditionalFunc):
|
|
result = []
|
|
additionalResult = []
|
|
invokeMenuItem("Tools", "Options...")
|
|
waitForObjectItem(":Options_QListView", "Build & Run")
|
|
clickItem(":Options_QListView", "Build & Run", 14, 15, 0, Qt.LeftButton)
|
|
clickTab(waitForObject(":Options.qt_tabwidget_tabbar_QTabBar"), "Qt Versions")
|
|
pattern = re.compile("Qt version (?P<version>.*?) for (?P<target>.*)")
|
|
treeWidget = waitForObject(":QtSupport__Internal__QtVersionManager.qtdirList_QTreeWidget")
|
|
root = treeWidget.invisibleRootItem()
|
|
for childRow in range(root.childCount()):
|
|
rootChild = root.child(childRow)
|
|
rootChildText = str(rootChild.text(0)).replace(".", "\\.")
|
|
for row in range(rootChild.childCount()):
|
|
subChild = rootChild.child(row)
|
|
subChildText = str(subChild.text(0)).replace(".", "\\.")
|
|
clickItem(treeWidget, ".".join([rootChildText,subChildText]), 5, 5, 0, Qt.LeftButton)
|
|
currentText = str(waitForObject(":QtSupport__Internal__QtVersionManager.QLabel").text)
|
|
matches = pattern.match(currentText)
|
|
if matches:
|
|
target = matches.group("target").strip()
|
|
version = matches.group("version").strip()
|
|
result.append({target:version})
|
|
if additionalFunction:
|
|
try:
|
|
if isinstance(additionalFunction, (str, unicode)):
|
|
currResult = globals()[additionalFunction](target, version, *argsForAdditionalFunc)
|
|
else:
|
|
currResult = additionalFunction(target, version, *argsForAdditionalFunc)
|
|
except:
|
|
import sys
|
|
t,v,tb = sys.exc_info()
|
|
currResult = None
|
|
test.fatal("Function to additionally execute on Options Dialog could not be found or "
|
|
"an exception occured while executing it.", "%s(%s)" % (str(t), str(v)))
|
|
additionalResult.append(currResult)
|
|
if not keepOptionsOpen:
|
|
clickButton(waitForObject(":Options.Cancel_QPushButton"))
|
|
if additionalFunction:
|
|
return result, additionalResult
|
|
else:
|
|
return result
|