project.py 17.6 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
20

def openCmakeProject(projectPath):
    invokeMenuItem("File", "Open File or Project...")
21
    selectFromFileDialog(projectPath)
22
23
24
25
26
27
28
29
30
31
    clickButton(waitForObject(":CMake Wizard.Next_QPushButton", 20000))
    generatorCombo = waitForObject(":Generator:_QComboBox")
    index = generatorCombo.findText("MinGW Generator (MinGW from SDK)")
    if index == -1:
        index = generatorCombo.findText("NMake Generator (Microsoft Visual C++ Compiler 9.0 (x86))")
    if index != -1:
        generatorCombo.setCurrentIndex(index)
    clickButton(waitForObject(":CMake Wizard.Run CMake_QPushButton", 20000))
    clickButton(waitForObject(":CMake Wizard.Finish_QPushButton", 60000))

32
33
34
35
36
37
38
39
40
41
42
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"

43
44
45
46
47
48
49
50
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))

51
def __createProjectSetNameAndPath__(path, projectName = None, checks = True):
52
53
54
55
56
57
58
59
60
61
62
63
64
    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
65
    ensureChecked("{type='QCheckBox' name='projectsDirectoryCheckBox' visible='1'}", False)
66
    clickButton(waitForObject(":Next_QPushButton"))
67
    return str(projectName)
68

69
70
71
72
# 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
73
74
def __selectQtVersionDesktop__(qtVersion, checks):
    __chooseTargets__()
75
76
77
78
79
80
81
82
83
84
85
86
    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")
87
88
    clickButton(waitForObject(":Next_QPushButton"))

89
def __createProjectHandleLastPage__(expectedFiles = None):
90
    if expectedFiles != None:
91
92
        summary = str(waitForObject("{name='filesLabel' text?='<qt>Files to be added in<pre>*</pre>'"
                                    "type='QLabel' visible='1'}").text)
93
94
95
96
97
98
99
100
        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))

101
102
103
104
105
106
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")

107
108
109
110
111
112
113
# 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):
114
    __createProjectSelectType__("Other Qt Project", "Qt Gui Application")
115
    __createProjectSetNameAndPath__(path, projectName, checks)
116
    __selectQtVersionDesktop__(qtVersion, checks)
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

    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)

133
    clickButton(waitForObject(":Next_QPushButton"))
134

135
    expectedFiles = None
136
    if checks:
137
138
        if platform.system() in ('Windows', 'Microsoft'):
            path = os.path.abspath(path)
Robert Loehning's avatar
Robert Loehning committed
139
140
        path = os.path.join(path, projectName)
        expectedFiles = [path, cpp_file, h_file, ui_file, pro_file]
141
    __createProjectHandleLastPage__(expectedFiles)
142

143
144
145
146
147
148
149
    waitForSignal("{type='CppTools::Internal::CppModelManager' unnamed='1'}", "sourceFilesRefreshed(QStringList)", 20000)
    __verifyFileCreation__(path, expectedFiles)

def createProject_Qt_Console(path, projectName, qtVersion, checks):
    __createProjectSelectType__("Other Qt Project", "Qt Console Application")
    __createProjectSetNameAndPath__(path, projectName, checks)
    __selectQtVersionDesktop__(qtVersion, checks)
150

151
152
153
154
155
156
157
158
159
    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)
160

161
162
    waitForSignal("{type='CppTools::Internal::CppModelManager' unnamed='1'}", "sourceFilesRefreshed(QStringList)", 10000)
    __verifyFileCreation__(path, expectedFiles)
163

164
def createNewQtQuickApplication(workingDir, projectName = None, templateFile = None, targets = QtQuickConstants.Targets.DESKTOP):
165
    __createProjectSelectType__("Qt Quick Project", "Qt Quick Application")
166
    projectName = __createProjectSetNameAndPath__(workingDir, projectName)
167
    if (templateFile==None):
168
        __chooseComponents__()
169
    else:
170
        __chooseComponents__(QtQuickConstants.Components.EXISTING_QML)
171
172
173
        # define the existing qml file to import
        baseLineEd = waitForObject("{type='Utils::BaseValidatingLineEdit' unnamed='1' visible='1'}", 20000)
        type(baseLineEd, templateFile)
174
    nextButton = waitForObject(":Next_QPushButton", 20000)
175
    clickButton(nextButton)
176
    __chooseTargets__(targets)
177
178
    snooze(1)
    clickButton(nextButton)
179
    __createProjectHandleLastPage__()
180
    return projectName
181
182

def createNewQtQuickUI(workingDir):
183
    __createProjectSelectType__("Qt Quick Project", "Qt Quick UI")
184
185
    if workingDir == None:
        workingDir = tempDir()
186
    projectName = __createProjectSetNameAndPath__(workingDir)
187
    __createProjectHandleLastPage__()
188
    return projectName
189
190

def createNewQmlExtension(workingDir):
191
    __createProjectSelectType__("Qt Quick Project", "Custom QML Extension Plugin")
192
193
    if workingDir == None:
        workingDir = tempDir()
194
195
    __createProjectSetNameAndPath__(workingDir)
    __chooseTargets__()
196
    nextButton = waitForObject(":Next_QPushButton")
197
198
199
200
201
202
203
204
    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)
205
    __createProjectHandleLastPage__()
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289

# 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:
                test.fail("Failed to check target '%s'" % QtQuickConstants.getStringForTarget(current))

# 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
    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):
290
    ensureChecked(":Qt Creator_AppOutput_Core::Internal::OutputPaneToggleButton")
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
    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
306
    ensureChecked(":Qt Creator_AppOutput_Core::Internal::OutputPaneToggleButton")
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    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:
        test.fatal("Could not attach to '%s' - using fallback of pushing STOP inside Creator." % executable)
        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)