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("") snooze(1) nativeType(fileName) snooze(1) nativeType("") snooze(2) nativeType("") 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.*?) for (?P.*)") 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