/tests/system/shared/debugger.py
Python | 224 lines | 199 code | 10 blank | 15 comment | 45 complexity | 552758fa9fd4169987e74d29b39e39a9 MD5 | raw file
- import re
- def handleDebuggerWarnings(config):
- if "MSVC" in config:
- try:
- popup = waitForObject("{text?='<html><head/><body>*' type='QLabel' unnamed='1' visible='1' window=':Symbol Server_Utils::CheckableMessageBox'}", 10000)
- symServerNotConfiged = ("<html><head/><body><p>The debugger is not configured to use the public "
- "<a href=\"http://support.microsoft.com/kb/311503\">Microsoft Symbol Server</a>. "
- "This is recommended for retrieval of the symbols of the operating system libraries.</p>"
- "<p><i>Note:</i> A fast internet connection is required for this to work smoothly. "
- "Also, a delay might occur when connecting for the first time.</p>"
- "<p>Would you like to set it up?</p></br></body></html>")
- if popup.text == symServerNotConfiged:
- test.log("Creator warned about the debugger not being configured to use the public Microsoft Symbol Server.")
- else:
- test.warning("Creator showed an unexpected warning: " + str(popup.text))
- clickButton(waitForObject("{text='No' type='QPushButton' unnamed='1' visible='1' window=':Symbol Server_Utils::CheckableMessageBox'}", 10000))
- except LookupError:
- pass # No warning. Fine.
- else:
- if "Release" in config and platform.system() != "Darwin":
- message = waitForObject("{container=':Qt Creator.DebugModeWidget_QSplitter' name='qt_msgbox_label' type='QLabel' visible='1'}", 20000)
- test.compare(message.text, "This does not seem to be a \"Debug\" build.\nSetting breakpoints by file name and line number may fail.")
- clickButton("{container=':Qt Creator.DebugModeWidget_QSplitter' text='OK' type='QPushButton' unnamed='1' visible='1'}")
- def takeDebuggerLog():
- invokeMenuItem("Window", "Views", "Debugger Log")
- debuggerLogWindow = waitForObject("{container=':DebugModeWidget.Debugger Log_QDockWidget' type='Debugger::Internal::CombinedPane' unnamed='1' visible='1'}", 20000)
- debuggerLog = str(debuggerLogWindow.plainText)
- mouseClick(debuggerLogWindow, 5, 5, 0, Qt.LeftButton)
- activateItem(waitForObjectItem(openContextMenuOnTextCursorPosition(debuggerLogWindow),
- "Clear Contents"))
- waitFor("str(debuggerLogWindow.plainText)==''", 5000)
- invokeMenuItem("Window", "Views", "Debugger Log")
- return debuggerLog
- # function to set breakpoints for the current project
- # on the given file,line pairs inside the given dict
- # the lines are treated as regular expression
- def setBreakpointsForCurrentProject(filesAndLines):
- # internal helper for setBreakpointsForCurrentProject
- # double clicks the treeElement inside the given navTree
- # TODO: merge with doubleClickFile() from tst_qml_editor & move to utils(?)
- def __doubleClickFile__(navTree, treeElement):
- waitForObjectItem(navTree, treeElement)
- fileNamePattern = re.compile(".*\.(?P<file>(.*\\\..*)?)$")
- fileName = fileNamePattern.search(treeElement).group("file").replace("\\.", ".")
- doubleClickItem(navTree, treeElement, 5, 5, 0, Qt.LeftButton)
- mainWindow = waitForObject(":Qt Creator_Core::Internal::MainWindow")
- waitFor('fileName in str(mainWindow.windowTitle)', 5000)
- return fileName
- switchViewTo(ViewConstants.DEBUG)
- removeOldBreakpoints()
- if not filesAndLines or not isinstance(filesAndLines, dict):
- test.fatal("This function only takes a non-empty dict.")
- return False
- navTree = waitForObject("{type='Utils::NavigationTreeView' unnamed='1' visible='1' "
- "window=':Qt Creator_Core::Internal::MainWindow'}", 20000)
- for curFile,curLine in filesAndLines.iteritems():
- fName = __doubleClickFile__(navTree, curFile)
- editor = getEditorForFileSuffix(curFile)
- if not placeCursorToLine(editor, curLine, True):
- return False
- invokeMenuItem("Debug", "Toggle Breakpoint")
- test.log('Set breakpoint in %s' % fName, curLine)
- try:
- breakPointTreeView = waitForObject("{type='Debugger::Internal::BreakWindow' visible='1' "
- "windowTitle='Breakpoints' name='Debugger.Docks.Break'}")
- waitFor("breakPointTreeView.model().rowCount() == len(filesAndLines)", 2000)
- except:
- test.fatal("UI seems to have changed - check manually and fix this script.")
- return False
- test.compare(breakPointTreeView.model().rowCount(), len(filesAndLines),
- 'Expected %d set break points, found %d listed' %
- (len(filesAndLines), breakPointTreeView.model().rowCount()))
- return True
- # helper that removes all breakpoints - assumes that it's getting called
- # being already on Debug view and Breakpoints widget is not disabled
- def removeOldBreakpoints():
- test.log("Removing old breakpoints if there are any")
- try:
- breakPointTreeView = waitForObject("{type='Debugger::Internal::BreakWindow' visible='1' "
- "windowTitle='Breakpoints' name='Debugger.Docks.Break'}")
- model = breakPointTreeView.model()
- if model.rowCount()==0:
- test.log("No breakpoints found...")
- else:
- test.log("Found %d breakpoints - removing them" % model.rowCount())
- for row in range(model.rowCount()):
- currentIndex = model.index(row,0)
- rect = breakPointTreeView.visualRect(currentIndex)
- mouseClick(breakPointTreeView, rect.x+5, rect.y+5, 0, Qt.LeftButton)
- type(breakPointTreeView, "<Delete>")
- except:
- test.fatal("UI seems to have changed - check manually and fix this script.")
- return False
- return test.compare(model.rowCount(), 0, "Check if all breakpoints have been removed.")
- # function to do simple debugging of the current (configured) project
- # param pressContinueCount defines how often it is expected to press
- # the 'Continue' button while debugging
- # param expectedBPOrder holds a list of dicts where the dicts contain always
- # only 1 key:value pair - the key is the name of the file, the value is
- # line number where the debugger should stop
- def doSimpleDebugging(currentConfigName, pressContinueCount=1, expectedBPOrder=[]):
- expectedLabelTexts = ['Stopped\.', 'Stopped at breakpoint \d+ \(\d+\) in thread \d+\.']
- if len(expectedBPOrder) == 0:
- expectedLabelTexts.append("Running\.")
- if not __startDebugger__(currentConfigName):
- return False
- statusLabel = findObject(":Debugger Toolbar.StatusText_Utils::StatusLabel")
- test.log("Continuing debugging %d times..." % pressContinueCount)
- for i in range(pressContinueCount):
- if waitFor("regexVerify(str(statusLabel.text), expectedLabelTexts)", 20000):
- verifyBreakPoint(expectedBPOrder[i])
- else:
- test.fail('%s' % str(statusLabel.text))
- contDbg = waitForObject(":*Qt Creator.Continue_Core::Internal::FancyToolButton", 3000)
- test.log("Continuing...")
- clickButton(contDbg)
- waitFor("str(statusLabel.text) == 'Running.'", 5000)
- timedOut = not waitFor("str(statusLabel.text) in ['Running.', 'Debugger finished.']", 30000)
- if timedOut:
- test.log("Waiting for 'Running.' / 'Debugger finished.' timed out.",
- "Debugger is in state: '%s'..." % statusLabel.text)
- if str(statusLabel.text) == 'Running.':
- test.log("Debugger is still running... Will be stopped.")
- return __stopDebugger__()
- elif str(statusLabel.text) == 'Debugger finished.':
- test.log("Debugger has finished.")
- return __logDebugResult__()
- else:
- test.log("Trying to stop debugger...")
- try:
- return __stopDebugger__()
- except:
- # if stopping failed - debugger had already stopped
- return True
- def __startDebugger__(config):
- clickButton(waitForObject(":*Qt Creator.Start Debugging_Core::Internal::FancyToolButton"))
- handleDebuggerWarnings(config)
- hasNotTimedOut = waitFor("object.exists(':Debugger Toolbar.Continue_QToolButton')", 60000)
- try:
- mBox = findObject(":Failed to start application_QMessageBox")
- mBoxText = mBox.text
- mBoxIText = mBox.informativeText
- clickButton(":DebugModeWidget.OK_QPushButton")
- test.fail("Debugger hasn't started... QMessageBox appeared!")
- test.log("QMessageBox content: '%s'" % mBoxText,
- "'%s'" % mBoxIText)
- return False
- except:
- pass
- if hasNotTimedOut:
- test.passes("Debugger started...")
- else:
- test.fail("Debugger seems to have not started...")
- if "MSVC" in config:
- debuggerLog = takeDebuggerLog()
- if "lib\qtcreatorcdbext64\qtcreatorcdbext.dll cannot be found." in debuggerLog:
- test.fatal("qtcreatorcdbext.dll is missing in lib\qtcreatorcdbext64")
- else:
- test.fatal("Debugger log did not behave as expected. Please check manually.")
- logApplicationOutput()
- return False
- try:
- waitForObject(":*Qt Creator.Interrupt_Core::Internal::FancyToolButton", 3000)
- test.passes("'Interrupt' (debugger) button visible.")
- except:
- try:
- waitForObject(":*Qt Creator.Continue_Core::Internal::FancyToolButton", 3000)
- test.passes("'Continue' (debugger) button visible.")
- except:
- test.fatal("Neither 'Interrupt' nor 'Continue' button visible (Debugger).")
- return True
- def __stopDebugger__():
- clickButton(waitForObject(":Debugger Toolbar.Exit Debugger_QToolButton"))
- ensureChecked("{type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' "
- "window=':Qt Creator_Core::Internal::MainWindow' occurrence='3'}")
- output = waitForObject("{type='Core::OutputWindow' visible='1' windowTitle='Application Output Window'}", 20000)
- waitFor("'Debugging has finished' in str(output.plainText)", 20000)
- return __logDebugResult__()
- def __logDebugResult__():
- try:
- result = waitForObject(":*Qt Creator.Start Debugging_Core::Internal::FancyToolButton")
- test.passes("'Start Debugging' button visible.")
- except:
- test.fail("'Start Debugging' button is not visible.")
- result = None
- if result:
- test.passes("Debugger stopped.. Qt Creator is back at normal state.")
- else:
- test.fail("Debugger seems to have not stopped...")
- logApplicationOutput()
- return result
- def verifyBreakPoint(bpToVerify):
- if isinstance(bpToVerify, dict):
- fileName = bpToVerify.keys()[0]
- editor = getEditorForFileSuffix(fileName)
- if editor == None:
- return False
- textPos = editor.textCursor().position()
- line = str(editor.plainText)[:textPos].count("\n") + 1
- windowTitle = str(waitForObject(":Qt Creator_Core::Internal::MainWindow").windowTitle)
- if fileName in windowTitle:
- test.passes("Creator's window title changed according to current file")
- else:
- test.fail("Creator's window title did not change according to current file")
- if line == bpToVerify.values()[0]:
- test.passes("Breakpoint at expected line (%d) inside expected file (%s)"
- % (line, fileName))
- return True
- else:
- test.fail("Breakpoint did not match expected line/file",
- "Found: %d in %s" % (line, fileName))
- else:
- test.fatal("Expected a dict for bpToVerify - got '%s'" % className(bpToVerify))
- return False