project.py 19.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
processStarted = False
processExited = False

def __handleProcessStarted__(object):
    global processStarted
    processStarted = True

def __handleProcessExited__(object, exitCode):
    global processExited
    processExited = True

12 13
def openQmakeProject(projectPath):
    invokeMenuItem("File", "Open File or Project...")
14
    selectFromFileDialog(projectPath)
15 16
    waitForObject("{type='Qt4ProjectManager::Internal::ProjectLoadWizard' visible='1' windowTitle='Project Setup'}")
    selectFromCombo(":scrollArea.Create Build Configurations:_QComboBox", "For Each Qt Version One Debug And One Release")
17
    clickButton(waitForObject("{text~='(Finish|Done)' type='QPushButton'}"))
18

19
def openCmakeProject(projectPath, buildDir):
20
    invokeMenuItem("File", "Open File or Project...")
21
    selectFromFileDialog(projectPath)
22 23
    replaceEditorContent("{type='Utils::BaseValidatingLineEdit' unnamed='1' visible='1'"
                         "window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'}", buildDir)
24 25
    clickButton(waitForObject(":CMake Wizard.Next_QPushButton", 20000))
    generatorCombo = waitForObject(":Generator:_QComboBox")
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
    mkspec = __getMkspecFromQmake__("qmake")
    test.log("Using mkspec '%s'" % mkspec)

    if "win32-" in mkspec:
        generatorName = {"win32-g++" : "MinGW Generator (MinGW from SDK)",
                         "win32-msvc2008" : "NMake Generator (Microsoft Visual C++ Compiler 9.0 (x86))",
                         "win32-msvc2010" : "NMake Generator (Microsoft Visual C++ Compiler 10.0 (x86))"}
        index = -1
        if mkspec in generatorName:
            index = generatorCombo.findText(generatorName[mkspec])
        if index == -1:
            test.warning("No matching CMake generator for mkspec '%s' found." % mkspec)
        else:
            generatorCombo.setCurrentIndex(index)

41
    clickButton(waitForObject(":CMake Wizard.Run CMake_QPushButton", 20000))
Christian Stenger's avatar
Christian Stenger committed
42 43 44 45 46 47 48 49 50 51
    try:
        clickButton(waitForObject(":CMake Wizard.Finish_QPushButton", 60000))
    except LookupError:
        cmakeOutput = waitForObject("{type='QPlainTextEdit' unnamed='1' visible='1' "
                                    "window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'}")
        test.warning("Error while executing cmake - see details for cmake output.",
                     str(cmakeOutput.plainText))
        clickButton(waitForObject(":CMake Wizard.Cancel_QPushButton"))
        return False
    return True
52

53 54 55 56 57 58 59 60 61 62 63
def shadowBuildDir(path, project, qtVersion, debugVersion):
    qtVersion = qtVersion.replace(" ", "_")
    qtVersion = qtVersion.replace(".", "_")
    qtVersion = qtVersion.replace("(", "_")
    qtVersion = qtVersion.replace(")", "_")
    buildDir = path + os.sep + project + "-build-desktop-" + qtVersion
    if debugVersion:
        return buildDir + "_Debug"
    else:
        return buildDir + "_Release"

64 65 66 67 68 69 70 71
def __createProjectSelectType__(category, template):
    invokeMenuItem("File", "New File or Project...")
    categoriesView = waitForObject("{type='QTreeView' name='templateCategoryView'}", 20000)
    clickItem(categoriesView, "Projects." + category, 5, 5, 0, Qt.LeftButton)
    templatesView = waitForObject("{name='templatesView' type='QListView'}", 20000)
    clickItem(templatesView, template, 5, 5, 0, Qt.LeftButton)
    clickButton(waitForObject("{text='Choose...' type='QPushButton' unnamed='1' visible='1'}", 20000))

72
def __createProjectSetNameAndPath__(path, projectName = None, checks = True):
73 74 75 76 77 78 79 80 81 82 83 84 85
    directoryEdit = waitForObject("{type='Utils::BaseValidatingLineEdit' unnamed='1' visible='1'}", 20000)
    replaceEditorContent(directoryEdit, path)
    projectNameEdit = waitForObject("{name='nameLineEdit' visible='1' "
                                    "type='Utils::ProjectNameValidatingLineEdit'}", 20000)
    if projectName == None:
        projectName = projectNameEdit.text
    else:
        replaceEditorContent(projectNameEdit, projectName)
    if checks:
        stateLabel = findObject("{type='QLabel' name='stateLabel'}")
        labelCheck = stateLabel.text=="" and stateLabel.styleSheet == ""
        test.verify(labelCheck, "Project name and base directory without warning or error")
    # make sure this is not set as default location
86
    ensureChecked("{type='QCheckBox' name='projectsDirectoryCheckBox' visible='1'}", False)
87
    clickButton(waitForObject(":Next_QPushButton"))
88
    return str(projectName)
89

90 91 92 93
# Selects the Qt versions for a project
# param qtVersion is the name of a Qt version. In the project, build configurations will be
#                 created for this version. If it is None, all Qt versions will be used
# param checks turns tests in the function on if set to True
94 95
def __selectQtVersionDesktop__(qtVersion, checks):
    __chooseTargets__()
96 97 98 99 100 101 102 103 104 105 106 107
    if qtVersion == None:
        selectFromCombo(":scrollArea.Create Build Configurations:_QComboBox_2",
                        "For Each Qt Version One Debug And One Release")
        ensureChecked(":scrollArea.Use Shadow Building_QCheckBox")
    else:
        selectFromCombo(":scrollArea.Create Build Configurations:_QComboBox_2",
                        "For One Qt Version One Debug And One Release")
        ensureChecked(":scrollArea.Use Shadow Building_QCheckBox")
        selectFromCombo(":scrollArea.Qt Version:_QComboBox", qtVersion)
        if checks:
            verifyChecked(":scrollArea.Qt 4 for Desktop - (Qt SDK) debug_QCheckBox")
            verifyChecked(":scrollArea.Qt 4 for Desktop - (Qt SDK) release_QCheckBox")
108 109
    clickButton(waitForObject(":Next_QPushButton"))

110
def __createProjectHandleLastPage__(expectedFiles = None):
111
    if expectedFiles != None:
112 113
        summary = str(waitForObject("{name='filesLabel' text?='<qt>Files to be added in<pre>*</pre>'"
                                    "type='QLabel' visible='1'}").text)
114 115 116 117 118 119 120 121
        lastIndex = 0
        for filename in expectedFiles:
            index = summary.find(filename)
            test.verify(index > lastIndex, "'" + filename + "' found at index " + str(index))
            lastIndex = index
    selectFromCombo(":addToVersionControlComboBox_QComboBox", "<None>")
    clickButton(waitForObject("{type='QPushButton' text~='(Finish|Done)' visible='1'}", 20000))

122 123 124 125 126 127
def __verifyFileCreation__(path, expectedFiles):
    for filename in expectedFiles:
        if filename != path:
            filename = os.path.join(path, filename)
        test.verify(os.path.exists(filename), "Checking if '" + filename + "' was created")

128 129 130 131 132 133 134
# Creates a Qt GUI project
# param path specifies where to create the project
# param projectName is the name for the new project
# param qtVersion is the name of a Qt version. In the project, build configurations will be
#                 created for this version. If it is None, all Qt versions will be used
# param checks turns tests in the function on if set to True
def createProject_Qt_GUI(path, projectName, qtVersion = None, checks = True):
135
    __createProjectSelectType__("Other Qt Project", "Qt Gui Application")
136
    __createProjectSetNameAndPath__(path, projectName, checks)
137
    __selectQtVersionDesktop__(qtVersion, checks)
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

    if checks:
        exp_filename = "mainwindow"
        h_file = exp_filename + ".h"
        cpp_file = exp_filename + ".cpp"
        ui_file = exp_filename + ".ui"
        pro_file = projectName + ".pro"

        waitFor("object.exists(':headerFileLineEdit_Utils::FileNameValidatingLineEdit')", 20000)
        waitFor("object.exists(':sourceFileLineEdit_Utils::FileNameValidatingLineEdit')", 20000)
        waitFor("object.exists(':formFileLineEdit_Utils::FileNameValidatingLineEdit')", 20000)

        test.compare(findObject(":headerFileLineEdit_Utils::FileNameValidatingLineEdit").text, h_file)
        test.compare(findObject(":sourceFileLineEdit_Utils::FileNameValidatingLineEdit").text, cpp_file)
        test.compare(findObject(":formFileLineEdit_Utils::FileNameValidatingLineEdit").text, ui_file)

154
    clickButton(waitForObject(":Next_QPushButton"))
155

156
    expectedFiles = None
157
    if checks:
158 159
        if platform.system() in ('Windows', 'Microsoft'):
            path = os.path.abspath(path)
Robert Loehning's avatar
Robert Loehning committed
160 161
        path = os.path.join(path, projectName)
        expectedFiles = [path, cpp_file, h_file, ui_file, pro_file]
162
    __createProjectHandleLastPage__(expectedFiles)
163

164 165 166
    waitForSignal("{type='CppTools::Internal::CppModelManager' unnamed='1'}", "sourceFilesRefreshed(QStringList)", 20000)
    __verifyFileCreation__(path, expectedFiles)

167 168 169 170 171 172 173
# Creates a Qt Console project
# param path specifies where to create the project
# param projectName is the name for the new project
# param qtVersion is the name of a Qt version. In the project, build configurations will be
#                 created for this version. If it is None, all Qt versions will be used
# param checks turns tests in the function on if set to True
def createProject_Qt_Console(path, projectName, qtVersion = None, checks = True):
174 175 176
    __createProjectSelectType__("Other Qt Project", "Qt Console Application")
    __createProjectSetNameAndPath__(path, projectName, checks)
    __selectQtVersionDesktop__(qtVersion, checks)
177

178 179 180 181 182 183 184 185 186
    expectedFiles = None
    if checks:
        if platform.system() in ('Windows', 'Microsoft'):
            path = os.path.abspath(path)
        path = os.path.join(path, projectName)
        cpp_file = "main.cpp"
        pro_file = projectName + ".pro"
        expectedFiles = [path, cpp_file, pro_file]
    __createProjectHandleLastPage__(expectedFiles)
187

188 189
    waitForSignal("{type='CppTools::Internal::CppModelManager' unnamed='1'}", "sourceFilesRefreshed(QStringList)", 10000)
    __verifyFileCreation__(path, expectedFiles)
190

191
def createNewQtQuickApplication(workingDir, projectName = None, templateFile = None, targets = QtQuickConstants.Targets.DESKTOP):
192
    __createProjectSelectType__("Qt Quick Project", "Qt Quick Application")
193
    projectName = __createProjectSetNameAndPath__(workingDir, projectName)
194
    if (templateFile==None):
195
        __chooseComponents__()
196
    else:
197
        __chooseComponents__(QtQuickConstants.Components.EXISTING_QML)
198 199 200
        # define the existing qml file to import
        baseLineEd = waitForObject("{type='Utils::BaseValidatingLineEdit' unnamed='1' visible='1'}", 20000)
        type(baseLineEd, templateFile)
201
    nextButton = waitForObject(":Next_QPushButton", 20000)
202
    clickButton(nextButton)
203
    __chooseTargets__(targets)
204 205
    snooze(1)
    clickButton(nextButton)
206
    __createProjectHandleLastPage__()
207
    return projectName
208 209

def createNewQtQuickUI(workingDir):
210
    __createProjectSelectType__("Qt Quick Project", "Qt Quick UI")
211 212
    if workingDir == None:
        workingDir = tempDir()
213
    projectName = __createProjectSetNameAndPath__(workingDir)
214
    __createProjectHandleLastPage__()
215
    return projectName
216 217

def createNewQmlExtension(workingDir):
218
    __createProjectSelectType__("Qt Quick Project", "Custom QML Extension Plugin")
219 220
    if workingDir == None:
        workingDir = tempDir()
221 222
    __createProjectSetNameAndPath__(workingDir)
    __chooseTargets__()
223
    nextButton = waitForObject(":Next_QPushButton")
224 225 226 227 228 229 230 231
    clickButton(nextButton)
    nameLineEd = waitForObject("{buddy={type='QLabel' text='Object Class-name:' unnamed='1' visible='1'} "
                               "type='QLineEdit' unnamed='1' visible='1'}", 20000)
    replaceEditorContent(nameLineEd, "TestItem")
    uriLineEd = waitForObject("{buddy={type='QLabel' text='URI:' unnamed='1' visible='1'} "
                              "type='QLineEdit' unnamed='1' visible='1'}", 20000)
    replaceEditorContent(uriLineEd, "com.nokia.test.qmlcomponents")
    clickButton(nextButton)
232
    __createProjectHandleLastPage__()
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

# parameter components can only be one of the Constants defined in QtQuickConstants.Components
def __chooseComponents__(components=QtQuickConstants.Components.BUILTIN):
    rbComponentToChoose = waitForObject("{type='QRadioButton' text='%s' visible='1'}"
                              % QtQuickConstants.getStringForComponents(components), 20000)
    if rbComponentToChoose.checked:
        test.passes("Selected QRadioButton is '%s'" % QtQuickConstants.getStringForComponents(components))
    else:
        clickButton(rbComponentToChoose)
        test.verify(rbComponentToChoose.checked, "Selected QRadioButton is '%s'"
                % QtQuickConstants.getStringForComponents(components))

# parameter target can be an OR'd value of QtQuickConstants.Targets
def __chooseTargets__(targets=QtQuickConstants.Targets.DESKTOP):
     # DESKTOP should be always accessible
    ensureChecked("{type='QCheckBox' text='%s' visible='1'}"
                  % QtQuickConstants.getStringForTarget(QtQuickConstants.Targets.DESKTOP),
                  targets & QtQuickConstants.Targets.DESKTOP)
    # following targets depend on the build environment - added for further/later tests
    available = [QtQuickConstants.Targets.MAEMO5,
                 QtQuickConstants.Targets.SIMULATOR, QtQuickConstants.Targets.HARMATTAN]
    if platform.system() in ('Windows', 'Microsoft'):
        available += [QtQuickConstants.Targets.SYMBIAN]
    for current in available:
        mustCheck = targets & current == current
        try:
            ensureChecked("{type='QCheckBox' text='%s' visible='1'}" % QtQuickConstants.getStringForTarget(current),
                          mustCheck)
        except LookupError:
            if mustCheck:
263 264 265
                test.fail("Failed to check target '%s'." % QtQuickConstants.getStringForTarget(current))
            else:
                test.warning("Target '%s' is not set up correctly." % QtQuickConstants.getStringForTarget(current))
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295

# run and close an application
# withHookInto - if set to True the function tries to attach to the sub-process instead of simply pressing Stop inside Creator
# executable - must be defined when using hook-into
# port - must be defined when using hook-into
# function - can be a string holding a function name or a reference to the function itself - this function will be called on
# the sub-process when hooking-into has been successful - if its missing simply closing the Qt Quick app will be done
# sType the SubprocessType - is nearly mandatory - except when using the function parameter
# userDefinedType - if you set sType to SubprocessType.USER_DEFINED you must(!) specify the WindowType for hooking into
# by yourself (or use the function parameter)
# ATTENTION! Make sure this function won't fail and the sub-process will end when the function returns
def runAndCloseApp(withHookInto=False, executable=None, port=None, function=None, sType=None, userDefinedType=None):
    global processStarted, processExited
    processStarted = processExited = False
    installLazySignalHandler("{type='ProjectExplorer::ApplicationLaucher'}", "processStarted()", "__handleProcessStarted__")
    installLazySignalHandler("{type='ProjectExplorer::ApplicationLaucher'}", "processExited(int)", "__handleProcessExited__")
    runButton = waitForObject("{type='Core::Internal::FancyToolButton' text='Run' visible='1'}", 20000)
    clickButton(runButton)
    if sType != SubprocessType.QT_QUICK_UI:
        waitForSignal("{type='ProjectExplorer::BuildManager' unnamed='1'}", "buildQueueFinished(bool)", 300000)
        buildSucceeded = checkLastBuild()
        if not buildSucceeded:
            test.fatal("Build inside run wasn't successful - leaving test")
            invokeMenuItem("File", "Exit")
            return False
    waitFor("processStarted==True", 10000)
    if not processStarted:
        test.fatal("Couldn't start application - leaving test")
        invokeMenuItem("File", "Exit")
        return False
296 297
    if os.getenv("SYSTEST_QMLVIEWER_NO_HOOK_INTO", "0") == "1":
        withHookInto = False
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    if withHookInto and not validType(sType, userDefinedType):
        if function != None:
            test.warning("You did not provide a valid value for the SubprocessType value - sType, but you have "
                         "provided a function to execute on the subprocess. Please ensure that your function "
                         "closes the subprocess before exiting, or this test will not complete.")
        else:
            test.warning("You did not provide a valid value for the SubprocessType value - sType, nor a "
                         "function to execute on the subprocess. Falling back to pushing the STOP button "
                         "inside creator to terminate execution of the subprocess.")
            withHookInto = False
    if withHookInto and not executable in ("", None):
        __closeSubprocessByHookingInto__(executable, port, function, sType, userDefinedType)
    else:
        __closeSubprocessByPushingStop__(sType)
    return True

def validType(sType, userDef):
    if sType == None:
        return False
    ty = SubprocessType.getWindowType(sType)
    return ty != None and not (ty == "user-defined" and (userDef == None or userDef.strip() == ""))

def __closeSubprocessByPushingStop__(sType):
321
    ensureChecked(":Qt Creator_AppOutput_Core::Internal::OutputPaneToggleButton")
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
    playButton = verifyEnabled(":Qt Creator.ReRun_QToolButton", False)
    stopButton = verifyEnabled(":Qt Creator.Stop_QToolButton")
    if stopButton.enabled:
        clickButton(stopButton)
        test.verify(playButton.enabled)
        test.compare(stopButton.enabled, False)
        if sType == SubprocessType.QT_QUICK_UI and platform.system() == "Darwin":
            waitFor("stop.enabled==False")
            snooze(2)
            nativeType("<Escape>")
    else:
        test.fatal("Subprocess does not seem to have been started.")

def __closeSubprocessByHookingInto__(executable, port, function, sType, userDefType):
    global processExited
337
    ensureChecked(":Qt Creator_AppOutput_Core::Internal::OutputPaneToggleButton")
338 339 340 341 342 343 344 345
    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)
    try:
        attachToApplication(executable)
    except:
346
        test.warning("Could not attach to '%s' - using fallback of pushing STOP inside Creator." % executable)
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
        resetApplicationContextToCreator()
        __closeSubprocessByPushingStop__(sType)
        return False
    if function == None:
        if sType==SubprocessType.USER_DEFINED:
            sendEvent("QCloseEvent", "{type='%s' unnamed='1' visible='1'}" % userDefType)
        else:
            sendEvent("QCloseEvent", "{type='%s' unnamed='1' visible='1'}" % SubprocessType.getWindowType(sType))
        resetApplicationContextToCreator()
    else:
        try:
            if isinstance(function, (str, unicode)):
                globals()[function]()
            else:
                function()
        except:
            test.fatal("Function to execute on sub-process could not be found.",
                       "Using fallback of pushing STOP inside Creator.")
            resetApplicationContextToCreator()
            __closeSubprocessByPushingStop__(sType)
    waitFor("processExited==True", 10000)
    if not processExited:
        test.warning("Sub-process seems not to have closed properly.")
        try:
            resetApplicationContextToCreator()
            __closeSubprocessByPushingStop__(sType)
        except:
            pass
    return True

# this helper tries to reset the current application context back
# to creator - this strange work-around is needed _sometimes_ on MacOS
def resetApplicationContextToCreator():
    appCtxt = applicationContext("qtcreator")
    if appCtxt.name == "":
        appCtxt = applicationContext("Qt Creator")
    setApplicationContext(appCtxt)