2016-01-15 14:55:33 +01:00
|
|
|
# Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2013-05-15 13:17:33 +02:00
|
|
|
|
2018-11-02 09:47:38 +01:00
|
|
|
def jumpToFirstLine(editor):
|
|
|
|
home = "<Home>" if platform.system() == 'Darwin' else "<Ctrl+Home>"
|
|
|
|
type(editor, home)
|
|
|
|
|
2011-09-21 17:29:18 +02:00
|
|
|
# places the cursor inside the given editor into the given line
|
|
|
|
# (leading and trailing whitespaces are ignored!)
|
|
|
|
# and goes to the end of the line
|
|
|
|
# line can be a regex - but if so, remember to set isRegex to True
|
|
|
|
# the function returns True if this went fine, False on error
|
2012-05-23 15:36:30 +02:00
|
|
|
def placeCursorToLine(editor, line, isRegex=False):
|
2012-10-01 12:16:56 +02:00
|
|
|
def getEditor():
|
|
|
|
return waitForObject(editor)
|
|
|
|
|
|
|
|
isDarwin = platform.system() == 'Darwin'
|
2021-10-29 14:38:35 +02:00
|
|
|
if not isString(editor):
|
2012-10-01 12:16:56 +02:00
|
|
|
editor = objectMap.realName(editor)
|
2011-09-21 17:29:18 +02:00
|
|
|
oldPosition = 0
|
2018-11-02 09:47:38 +01:00
|
|
|
jumpToFirstLine(getEditor())
|
2011-09-21 17:29:18 +02:00
|
|
|
found = False
|
|
|
|
if isRegex:
|
|
|
|
regex = re.compile(line)
|
|
|
|
while not found:
|
2012-10-01 12:16:56 +02:00
|
|
|
currentLine = str(lineUnderCursor(getEditor())).strip()
|
2012-05-23 15:36:30 +02:00
|
|
|
found = isRegex and regex.match(currentLine) or not isRegex and currentLine == line
|
|
|
|
if not found:
|
2012-10-01 12:16:56 +02:00
|
|
|
type(getEditor(), "<Down>")
|
|
|
|
newPosition = getEditor().textCursor().position()
|
2012-05-23 15:36:30 +02:00
|
|
|
if oldPosition == newPosition:
|
|
|
|
break
|
|
|
|
oldPosition = newPosition
|
2011-09-21 17:29:18 +02:00
|
|
|
if not found:
|
|
|
|
test.fatal("Couldn't find line matching\n\n%s\n\nLeaving test..." % line)
|
|
|
|
return False
|
2012-10-01 12:16:56 +02:00
|
|
|
if isDarwin:
|
|
|
|
type(getEditor(), "<Ctrl+Right>")
|
|
|
|
else:
|
|
|
|
type(getEditor(), "<End>")
|
2011-09-21 17:29:18 +02:00
|
|
|
return True
|
|
|
|
|
2021-04-21 20:43:09 +02:00
|
|
|
# returns the number of the text line where the cursor is, starting at line 1
|
|
|
|
# param editor is the editor the cursor is in
|
|
|
|
def lineNumberWithCursor(editor):
|
|
|
|
textPos = editor.textCursor().position()
|
|
|
|
line = str(editor.plainText)[:textPos].count("\n") + 1
|
|
|
|
return line
|
|
|
|
|
2012-01-24 17:47:12 +01:00
|
|
|
# this function returns True if a QMenu is
|
|
|
|
# popped up above the given editor
|
|
|
|
# param editor is the editor where the menu should appear
|
|
|
|
# param menuInList is a list containing one item. This item will be assigned the menu if there is one.
|
|
|
|
# THIS IS A HACK to get a pass-by-reference
|
|
|
|
def menuVisibleAtEditor(editor, menuInList):
|
|
|
|
menuInList[0] = None
|
|
|
|
try:
|
2013-02-11 17:29:08 +01:00
|
|
|
menu = waitForObject("{type='QMenu' unnamed='1' visible='1'}", 500)
|
2019-03-20 09:48:43 +01:00
|
|
|
topLeft = menu.mapToGlobal(QPoint(0, 0))
|
|
|
|
bottomLeft = menu.mapToGlobal(QPoint(0, menu.height))
|
2020-07-22 09:56:25 +02:00
|
|
|
center = menu.mapToGlobal(QPoint(menu.width / 2, menu.height / 2))
|
2019-03-20 09:48:43 +01:00
|
|
|
success = menu.visible and (widgetContainsPoint(editor, topLeft)
|
2020-07-22 09:56:25 +02:00
|
|
|
or widgetContainsPoint(editor, bottomLeft)
|
|
|
|
or widgetContainsPoint(editor, center))
|
2012-01-24 17:47:12 +01:00
|
|
|
if success:
|
|
|
|
menuInList[0] = menu
|
|
|
|
return success
|
|
|
|
except:
|
2019-03-19 15:00:57 +01:00
|
|
|
t, v = sys.exc_info()[:2]
|
2023-05-03 23:49:59 +02:00
|
|
|
test.log("Exception: %s" % t.__name__, str(v))
|
2012-01-24 17:47:12 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
# this function checks whether the given global point (QPoint)
|
|
|
|
# is contained in the given widget
|
|
|
|
def widgetContainsPoint(widget, point):
|
|
|
|
return QRect(widget.mapToGlobal(QPoint(0, 0)), widget.size).contains(point)
|
|
|
|
|
2011-09-21 17:29:18 +02:00
|
|
|
# this function simply opens the context menu inside the given editor
|
|
|
|
# at the same position where the text cursor is located at
|
|
|
|
def openContextMenuOnTextCursorPosition(editor):
|
|
|
|
rect = editor.cursorRect(editor.textCursor())
|
|
|
|
openContextMenu(editor, rect.x+rect.width/2, rect.y+rect.height/2, 0)
|
2012-01-24 17:47:12 +01:00
|
|
|
menuInList = [None]
|
|
|
|
waitFor("menuVisibleAtEditor(editor, menuInList)", 5000)
|
|
|
|
return menuInList[0]
|
2011-09-21 17:29:18 +02:00
|
|
|
|
2013-01-18 16:28:27 +01:00
|
|
|
# this function marks/selects the text inside the given editor from current cursor position
|
|
|
|
# param direction is one of "Left", "Right", "Up", "Down", but "End" and combinations work as well
|
|
|
|
# param typeCount defines how often the cursor will be moved in the given direction (while marking)
|
|
|
|
def markText(editor, direction, typeCount=1):
|
2018-08-02 13:45:34 +02:00
|
|
|
for _ in range(typeCount):
|
2013-01-18 16:28:27 +01:00
|
|
|
type(editor, "<Shift+%s>" % direction)
|
2011-09-21 17:29:18 +02:00
|
|
|
|
2011-09-26 15:24:49 +02:00
|
|
|
# works for all standard editors
|
|
|
|
def replaceEditorContent(editor, newcontent):
|
2014-08-18 14:37:17 +02:00
|
|
|
type(editor, "<Ctrl+a>")
|
2011-09-26 15:24:49 +02:00
|
|
|
type(editor, "<Delete>")
|
|
|
|
type(editor, newcontent)
|
2011-12-08 11:52:38 +01:00
|
|
|
|
|
|
|
def typeLines(editor, lines):
|
2021-10-29 14:38:35 +02:00
|
|
|
if isString(lines):
|
2011-12-08 11:52:38 +01:00
|
|
|
lines = [lines]
|
|
|
|
if isinstance(lines, (list, tuple)):
|
|
|
|
for line in lines:
|
|
|
|
type(editor, line)
|
2012-10-22 17:19:33 +02:00
|
|
|
type(editor, "<Return>")
|
2011-12-08 11:52:38 +01:00
|
|
|
else:
|
|
|
|
test.warning("Illegal parameter passed to typeLines()")
|
2011-12-19 11:18:24 +01:00
|
|
|
|
|
|
|
# function to verify hoverings on e.g. code inside of the given editor
|
|
|
|
# param editor the editor object
|
|
|
|
# param lines a list/tuple of regex that indicates which lines should be verified
|
|
|
|
# param additionalKeyPresses an array holding the additional typings to do (special chars for cursor movement)
|
|
|
|
# to get to the location (inside line) where to trigger the hovering (must be the same for all lines)
|
|
|
|
# param expectedTypes list/tuple holding the type of the (tool)tips that should occur (for each line)
|
|
|
|
# param expectedValues list/tuple of dict or list/tuple of strings regarding the types that have been used
|
|
|
|
# if it's a dict it indicates a property value pair, if it's a string it is type specific (e.g. color value for ColorTip)
|
|
|
|
# param alternativeValues same as expectedValues, but here you can submit alternatives - this is for example
|
|
|
|
# necessary if you do not add the correct documentation (from where the tip gets its content)
|
|
|
|
def verifyHoveringOnEditor(editor, lines, additionalKeyPresses, expectedTypes, expectedValues, alternativeValues=None):
|
|
|
|
counter = 0
|
|
|
|
for line in lines:
|
|
|
|
expectedVals = expectedValues[counter]
|
|
|
|
expectedType = expectedTypes[counter]
|
|
|
|
altVal = None
|
|
|
|
if isinstance(alternativeValues, (list, tuple)):
|
|
|
|
altVal = alternativeValues[counter]
|
|
|
|
counter += 1
|
|
|
|
placeCursorToLine(editor, line, True)
|
|
|
|
for ty in additionalKeyPresses:
|
|
|
|
type(editor, ty)
|
|
|
|
rect = editor.cursorRect(editor.textCursor())
|
2019-02-14 09:28:01 +01:00
|
|
|
expectedToolTip = "{type='QLabel' objectName='qcToolTip' visible='1'}"
|
2015-02-02 14:33:14 +01:00
|
|
|
# wait for similar tooltips to disappear
|
|
|
|
checkIfObjectExists(expectedToolTip, False, 1000, True)
|
2011-12-19 11:18:24 +01:00
|
|
|
sendEvent("QMouseEvent", editor, QEvent.MouseMove, rect.x+rect.width/2, rect.y+rect.height/2, Qt.NoButton, 0)
|
|
|
|
try:
|
2015-02-02 14:33:14 +01:00
|
|
|
tip = waitForObject(expectedToolTip)
|
2011-12-19 11:18:24 +01:00
|
|
|
except:
|
|
|
|
tip = None
|
|
|
|
if tip == None:
|
|
|
|
test.warning("Could not get %s for line containing pattern '%s'" % (expectedType,line))
|
|
|
|
else:
|
|
|
|
if expectedType == "ColorTip":
|
2013-09-12 17:24:00 +02:00
|
|
|
__handleColorTips__(tip, expectedVals, altVal)
|
2011-12-19 11:18:24 +01:00
|
|
|
elif expectedType == "TextTip":
|
|
|
|
__handleTextTips__(tip, expectedVals, altVal)
|
|
|
|
elif expectedType == "WidgetTip":
|
2020-04-16 23:51:26 +02:00
|
|
|
__handleWidgetTips__(tip, expectedVals)
|
2020-04-17 18:33:21 +02:00
|
|
|
sendEvent("QMouseEvent", editor, QEvent.MouseMove, 0, 0, Qt.NoButton, 0)
|
2012-02-21 14:36:25 +01:00
|
|
|
waitFor("isNull(tip)", 10000)
|
2011-12-19 11:18:24 +01:00
|
|
|
|
|
|
|
# helper function that handles verification of TextTip hoverings
|
|
|
|
# param textTip the TextTip object
|
|
|
|
# param expectedVals a dict holding property value pairs that must match
|
|
|
|
def __handleTextTips__(textTip, expectedVals, alternativeVals):
|
|
|
|
props = object.properties(textTip)
|
2018-08-02 13:45:34 +02:00
|
|
|
expFail = False
|
2011-12-19 11:18:24 +01:00
|
|
|
eResult = verifyProperties(props, expectedVals)
|
2023-03-28 14:59:36 +02:00
|
|
|
for val in eResult.values():
|
2011-12-19 11:18:24 +01:00
|
|
|
if not val:
|
|
|
|
expFail = True
|
|
|
|
break
|
|
|
|
if expFail and alternativeVals != None:
|
|
|
|
aResult = verifyProperties(props, alternativeVals)
|
|
|
|
else:
|
|
|
|
aResult = None
|
|
|
|
if not expFail:
|
|
|
|
test.passes("TextTip verified")
|
|
|
|
else:
|
2023-03-21 10:10:03 +01:00
|
|
|
for key,val in eResult.items():
|
2011-12-19 11:18:24 +01:00
|
|
|
if val == False:
|
|
|
|
if aResult and aResult.get(key):
|
|
|
|
test.passes("Property '%s' does not match expected, but alternative value" % key)
|
|
|
|
else:
|
|
|
|
aVal = None
|
|
|
|
if alternativeVals:
|
|
|
|
aVal = alternativeVals.get(key, None)
|
|
|
|
if aVal:
|
|
|
|
test.fail("Property '%s' does not match - expected '%s' or '%s', got '%s'" % (key, expectedVals.get(key), aVal, props.get(key)))
|
|
|
|
else:
|
|
|
|
test.fail("Property '%s' does not match - expected '%s', got '%s" % (key, expectedVals.get(key), props.get(key)))
|
|
|
|
else:
|
|
|
|
test.fail("Property '%s' could not be found inside properties" % key)
|
|
|
|
|
|
|
|
# helper function that handles verification of ColorTip hoverings
|
|
|
|
# param colTip the ColorTip object
|
|
|
|
# param expectedColor a single string holding the color the ColorTip should have
|
|
|
|
# Attention: because of being a non-standard Qt object it's not possible to
|
|
|
|
# verify colors which are (semi-)transparent!
|
2013-09-12 17:24:00 +02:00
|
|
|
def __handleColorTips__(colTip, expectedColor, alternativeColor):
|
|
|
|
def uint(value):
|
|
|
|
if value < 0:
|
|
|
|
return 0xffffffff + value + 1
|
|
|
|
return value
|
|
|
|
|
2011-12-19 11:18:24 +01:00
|
|
|
cmp = QColor()
|
2017-05-24 14:08:22 +02:00
|
|
|
cmp.setNamedColor(QString(expectedColor))
|
2013-09-12 17:24:00 +02:00
|
|
|
if alternativeColor:
|
|
|
|
alt = QColor()
|
2017-05-24 14:08:22 +02:00
|
|
|
alt.setNamedColor(QString(alternativeColor))
|
2013-09-12 17:24:00 +02:00
|
|
|
if cmp.alpha() != 255 or alternativeColor and alt.alpha() != 255:
|
2011-12-19 11:18:24 +01:00
|
|
|
test.warning("Cannot handle transparent colors - cancelling this verification")
|
|
|
|
return
|
2014-10-13 07:27:35 +02:00
|
|
|
dPM = colTip.grab(QRect(1, 1, colTip.width - 2, colTip.height - 2))
|
2011-12-19 11:18:24 +01:00
|
|
|
img = dPM.toImage()
|
|
|
|
rgb = img.pixel(1, 1)
|
|
|
|
rgb = QColor(rgb)
|
2013-09-12 17:24:00 +02:00
|
|
|
if rgb.rgba() == cmp.rgba() or alternativeColor and rgb.rgba() == alt.rgba():
|
2011-12-19 11:18:24 +01:00
|
|
|
test.passes("ColorTip verified")
|
|
|
|
else:
|
2013-09-12 17:24:00 +02:00
|
|
|
altColorText = ""
|
|
|
|
if alternativeColor:
|
|
|
|
altColorText = " or '%X'" % uint(alt.rgb())
|
|
|
|
test.fail("ColorTip does not match - expected color '%X'%s got '%X'"
|
|
|
|
% (uint(cmp.rgb()), altColorText, uint(rgb.rgb())))
|
2011-12-19 11:18:24 +01:00
|
|
|
|
2020-04-16 23:51:26 +02:00
|
|
|
# helper function that handles verification of WidgetTip hoverings
|
|
|
|
# param widgetTip the WidgetTip object
|
|
|
|
# param expectedVals a dict holding property value pairs that must match
|
|
|
|
def __handleWidgetTips__(widgetTip, expectedVals):
|
|
|
|
toplabel = waitForObject("{type='QLabel' objectName='qcWidgetTipTopLabel' visible='1'}")
|
|
|
|
foundText = str(toplabel.text)
|
|
|
|
try:
|
|
|
|
helplabel = waitForObject("{type='QLabel' objectName='qcWidgetTipHelpLabel' visible='1'}", 1000)
|
|
|
|
foundText += str(helplabel.text)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
test.compare(foundText, expectedVals["text"])
|
|
|
|
|
2011-12-19 11:18:24 +01:00
|
|
|
# function that checks whether all expected properties (including their values)
|
|
|
|
# match the given properties
|
|
|
|
# param properties a dict holding the properties to check
|
|
|
|
# param expectedProps a dict holding the key value pairs that must be found inside properties
|
|
|
|
# this function returns a dict holding the keys of the expectedProps - the value of each key
|
|
|
|
# is a boolean that indicates whether this key could have been found inside properties and
|
|
|
|
# the values matched or None if the key could not be found
|
|
|
|
def verifyProperties(properties, expectedProps):
|
|
|
|
if not isinstance(properties, dict) or not isinstance(expectedProps, dict):
|
|
|
|
test.warning("Wrong usage - both parameter must be of type dict")
|
|
|
|
return {}
|
|
|
|
result = {}
|
2023-03-21 10:10:03 +01:00
|
|
|
for key,val in expectedProps.items():
|
2011-12-19 11:18:24 +01:00
|
|
|
foundVal = properties.get(key, None)
|
|
|
|
if foundVal != None:
|
|
|
|
result[key] = val == foundVal
|
|
|
|
else:
|
|
|
|
result[key] = None
|
|
|
|
return result
|
2012-03-30 13:05:29 +02:00
|
|
|
|
2014-06-04 09:44:20 +02:00
|
|
|
def getEditorForFileSuffix(curFile, treeViewSyntax=False):
|
2012-03-30 13:05:29 +02:00
|
|
|
cppEditorSuffixes = ["cpp", "cc", "CC", "h", "H", "cp", "cxx", "C", "c++", "inl", "moc", "qdoc",
|
|
|
|
"tcc", "tpp", "t++", "c", "cu", "m", "mm", "hh", "hxx", "h++", "hpp", "hp"]
|
|
|
|
qmlEditorSuffixes = ["qml", "qmlproject", "js", "qs", "qtt"]
|
|
|
|
proEditorSuffixes = ["pro", "pri", "prf"]
|
2012-06-18 19:52:38 +02:00
|
|
|
glslEditorSuffixes= ["frag", "vert", "fsh", "vsh", "glsl", "shader", "gsh"]
|
2013-07-11 15:20:40 +02:00
|
|
|
pytEditorSuffixes = ["py", "pyw", "wsgi"]
|
2016-02-11 20:59:31 +01:00
|
|
|
binEditorSuffixes = ["bin"]
|
2012-03-30 13:05:29 +02:00
|
|
|
suffix = __getFileSuffix__(curFile)
|
2014-06-04 09:44:20 +02:00
|
|
|
expected = os.path.basename(curFile)
|
|
|
|
if treeViewSyntax:
|
|
|
|
expected = simpleFileName(curFile)
|
2014-06-03 10:19:33 +02:00
|
|
|
mainWindow = waitForObject(":Qt Creator_Core::Internal::MainWindow")
|
2017-08-29 17:48:37 +02:00
|
|
|
if not waitFor("str(mainWindow.windowTitle).startswith(expected + ' ')", 5000):
|
2014-06-03 10:19:33 +02:00
|
|
|
test.fatal("Window title (%s) did not switch to expected file (%s)."
|
2014-06-04 09:44:20 +02:00
|
|
|
% (str(mainWindow.windowTitle), expected))
|
2014-02-06 10:33:44 +01:00
|
|
|
try:
|
|
|
|
if suffix in cppEditorSuffixes:
|
|
|
|
editor = waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget")
|
|
|
|
elif suffix in qmlEditorSuffixes:
|
|
|
|
editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget")
|
2014-09-17 16:46:00 +02:00
|
|
|
elif suffix in proEditorSuffixes or suffix in glslEditorSuffixes or suffix in pytEditorSuffixes:
|
2014-10-08 12:31:37 +02:00
|
|
|
editor = waitForObject(":Qt Creator_TextEditor::TextEditorWidget")
|
2016-02-11 20:59:31 +01:00
|
|
|
elif suffix in binEditorSuffixes:
|
|
|
|
editor = waitForObject(":Qt Creator_BinEditor::BinEditorWidget")
|
2014-02-06 10:33:44 +01:00
|
|
|
else:
|
2014-10-08 12:31:37 +02:00
|
|
|
test.log("Trying TextEditorWidget (file suffix: %s)" % suffix)
|
2014-02-06 10:33:44 +01:00
|
|
|
try:
|
2014-10-08 12:31:37 +02:00
|
|
|
editor = waitForObject(":Qt Creator_TextEditor::TextEditorWidget", 3000)
|
2014-02-06 10:33:44 +01:00
|
|
|
except:
|
|
|
|
test.fatal("Unsupported file suffix for file '%s'" % curFile)
|
|
|
|
editor = None
|
|
|
|
except:
|
|
|
|
f = str(waitForObject(":Qt Creator_Core::Internal::MainWindow").windowTitle).split(" ", 1)[0]
|
|
|
|
if os.path.basename(curFile) == f:
|
|
|
|
test.fatal("Could not find editor although expected file matches.")
|
|
|
|
else:
|
|
|
|
test.fatal("Expected (%s) and current file (%s) do not match. Failed to get editor"
|
|
|
|
% (os.path.basename(curFile), f))
|
|
|
|
editor = None
|
2012-03-30 13:05:29 +02:00
|
|
|
return editor
|
|
|
|
|
|
|
|
# helper that determines the file suffix of the given fileName
|
|
|
|
# (doesn't matter if fileName contains the path as well)
|
|
|
|
def __getFileSuffix__(fileName):
|
|
|
|
suffix = os.path.basename(fileName).rsplit(".", 1)
|
|
|
|
if len(suffix) == 1:
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return suffix[1]
|
2012-04-23 13:17:40 +02:00
|
|
|
|
|
|
|
def maskSpecialCharsForSearchResult(filename):
|
|
|
|
filename = filename.replace("_", "\\_").replace(".","\\.")
|
|
|
|
return filename
|
|
|
|
|
2014-11-13 11:14:17 +01:00
|
|
|
def waitForSearchResults():
|
2014-11-17 16:16:48 +01:00
|
|
|
cancelButton = ("{text='Cancel' type='QToolButton' unnamed='1' visible='1' "
|
|
|
|
"window=':Qt Creator_Core::Internal::MainWindow'}")
|
2014-11-13 11:14:17 +01:00
|
|
|
|
2014-11-17 16:16:48 +01:00
|
|
|
waitFor("object.exists(cancelButton)", 3000)
|
|
|
|
waitFor("not object.exists(cancelButton)", 20000)
|
2014-11-13 11:14:17 +01:00
|
|
|
|
2012-04-23 13:17:40 +02:00
|
|
|
def validateSearchResult(expectedCount):
|
|
|
|
searchResult = waitForObject(":Qt Creator_SearchResult_Core::Internal::OutputPaneToggleButton")
|
|
|
|
ensureChecked(searchResult)
|
2014-02-13 13:15:33 +01:00
|
|
|
resultTreeView = waitForObject(":Qt Creator_Find::Internal::SearchResultTreeView")
|
2012-04-23 13:17:40 +02:00
|
|
|
counterLabel = waitForObject("{type='QLabel' unnamed='1' visible='1' text?='*matches found.' "
|
|
|
|
"window=':Qt Creator_Core::Internal::MainWindow'}")
|
|
|
|
matches = cast((str(counterLabel.text)).split(" ", 1)[0], "int")
|
|
|
|
test.compare(matches, expectedCount, "Verified match count.")
|
|
|
|
model = resultTreeView.model()
|
2012-10-25 12:59:03 +02:00
|
|
|
for index in dumpIndices(model):
|
2012-04-23 13:17:40 +02:00
|
|
|
itemText = str(model.data(index).toString())
|
|
|
|
doubleClickItem(resultTreeView, maskSpecialCharsForSearchResult(itemText), 5, 5, 0, Qt.LeftButton)
|
|
|
|
test.log("%d occurrences in %s" % (model.rowCount(index), itemText))
|
2012-10-25 12:59:03 +02:00
|
|
|
for chIndex in dumpIndices(model, index):
|
2012-04-23 13:17:40 +02:00
|
|
|
resultTreeView.scrollTo(chIndex)
|
2012-10-17 17:23:07 +02:00
|
|
|
text = str(chIndex.data()).rstrip('\r')
|
2012-04-23 13:17:40 +02:00
|
|
|
rect = resultTreeView.visualRect(chIndex)
|
2018-06-29 16:43:47 +02:00
|
|
|
doubleClick(resultTreeView, rect.x+50, rect.y+5, 0, Qt.LeftButton)
|
2012-04-23 13:17:40 +02:00
|
|
|
editor = getEditorForFileSuffix(itemText)
|
2014-03-18 21:32:38 +01:00
|
|
|
if not waitFor("lineUnderCursor(editor) == text", 2000):
|
|
|
|
test.warning("Jumping to search result '%s' is pretty slow." % text)
|
|
|
|
waitFor("lineUnderCursor(editor) == text", 2000)
|
2012-04-23 13:17:40 +02:00
|
|
|
test.compare(lineUnderCursor(editor), text)
|
|
|
|
|
|
|
|
# this function invokes context menu and command from it
|
|
|
|
def invokeContextMenuItem(editorArea, command1, command2 = None):
|
2022-12-15 08:25:56 +01:00
|
|
|
for _ in range(2):
|
|
|
|
ctxtMenu = openContextMenuOnTextCursorPosition(editorArea)
|
|
|
|
snooze(1)
|
|
|
|
try:
|
|
|
|
item1 = waitForObjectItem(objectMap.realName(ctxtMenu), command1, 2000)
|
|
|
|
break
|
|
|
|
except:
|
|
|
|
test.warning("Context menu item not ready (%s) - trying once more." % command1)
|
|
|
|
type(editorArea, "<Escape>")
|
|
|
|
|
2017-08-03 15:21:05 +02:00
|
|
|
if command2 and platform.system() == 'Darwin':
|
|
|
|
mouseMove(item1)
|
|
|
|
activateItem(item1)
|
2016-09-09 06:58:03 +02:00
|
|
|
if command2:
|
|
|
|
activateItem(waitForObjectItem("{title='%s' type='QMenu' visible='1' window=%s}"
|
|
|
|
% (command1, objectMap.realName(ctxtMenu)), command2, 2000))
|
2012-04-23 13:17:40 +02:00
|
|
|
|
|
|
|
# this function invokes the "Find Usages" item from context menu
|
|
|
|
# param editor an editor object
|
|
|
|
# param line a line in editor (content of the line as a string)
|
|
|
|
# param typeOperation a key to type
|
|
|
|
# param n how often repeat the type operation?
|
|
|
|
def invokeFindUsage(editor, line, typeOperation, n=1):
|
|
|
|
if not placeCursorToLine(editor, line, True):
|
|
|
|
return False
|
2018-08-02 13:45:34 +02:00
|
|
|
for _ in range(n):
|
2012-04-23 13:17:40 +02:00
|
|
|
type(editor, typeOperation)
|
2018-03-23 16:45:21 +01:00
|
|
|
snooze(1)
|
2019-02-13 15:32:26 +01:00
|
|
|
invokeContextMenuItem(editor, "Find References to Symbol Under Cursor")
|
2012-04-23 13:17:40 +02:00
|
|
|
return True
|
2012-10-09 15:00:17 +02:00
|
|
|
|
2013-01-30 18:15:38 +01:00
|
|
|
def addBranchWildcardToRoot(rootNode):
|
|
|
|
pos = rootNode.find(".")
|
2013-01-31 17:08:05 +01:00
|
|
|
if pos == -1:
|
2013-09-20 11:29:25 +02:00
|
|
|
return rootNode + " [[]*[]]"
|
|
|
|
return rootNode[:pos] + " [[]*[]]" + rootNode[pos:]
|
2013-01-30 18:15:38 +01:00
|
|
|
|
2012-10-09 15:00:17 +02:00
|
|
|
def openDocument(treeElement):
|
2022-12-15 12:57:29 +01:00
|
|
|
# split into tree elements
|
|
|
|
treePathElements = re.split(r"(?<!\\)\.", treeElement)
|
|
|
|
# 'unmask' the extension delimiter
|
|
|
|
treePathElements = list(x.replace("\\.", ".") for x in treePathElements)
|
2012-10-09 15:00:17 +02:00
|
|
|
try:
|
2022-12-15 12:57:29 +01:00
|
|
|
parentIndex = None
|
2013-09-17 19:35:05 +02:00
|
|
|
selectFromCombo(":Qt Creator_Core::Internal::NavComboBox", "Projects")
|
2012-10-09 15:00:17 +02:00
|
|
|
navigator = waitForObject(":Qt Creator_Utils::NavigationTreeView")
|
2022-12-15 12:57:29 +01:00
|
|
|
|
|
|
|
for i, t in enumerate(treePathElements):
|
|
|
|
indices = dumpIndices(navigator.model(), parentIndex)
|
|
|
|
foundT = False
|
|
|
|
for index in indices:
|
|
|
|
iText = str(index.text)
|
|
|
|
if (iText == t
|
|
|
|
or (i == 0 and re.match(t + " [[].+[]]", iText) is not None)):
|
|
|
|
foundT = True
|
|
|
|
parentIndex = index
|
|
|
|
break
|
|
|
|
if not foundT:
|
|
|
|
raise Exception("Failed to get index '%s' (%d)." % (t, i))
|
|
|
|
if not navigator.isExpanded(parentIndex):
|
|
|
|
navigator.scrollTo(parentIndex)
|
|
|
|
rect = navigator.visualRect(parentIndex)
|
|
|
|
doubleClick(navigator, rect.x + 50, rect.y + 5, 0, Qt.LeftButton)
|
|
|
|
# now we should have a full expanded tree up to the requested file
|
|
|
|
rect = navigator.visualRect(parentIndex)
|
|
|
|
doubleClick(navigator, rect.x + 50, rect.y + 5, 0, Qt.LeftButton)
|
|
|
|
mainWindow = waitForObject(":Qt Creator_Core::Internal::MainWindow")
|
2023-02-17 16:14:08 +01:00
|
|
|
fileNameWithoutLinePrefix = treePathElements[-1]
|
|
|
|
matching = re.match("^(.+)(:\\d+)$", fileNameWithoutLinePrefix)
|
|
|
|
if matching is not None:
|
|
|
|
fileNameWithoutLinePrefix = matching.group(1)
|
|
|
|
if waitFor("str(mainWindow.windowTitle).startswith(fileNameWithoutLinePrefix + ' ')", 5000):
|
2022-12-15 12:57:29 +01:00
|
|
|
return True
|
|
|
|
test.log("Expected file (%s) was not being opened in openDocument()" % treePathElements[-1])
|
2016-06-13 12:27:57 +02:00
|
|
|
return False
|
2012-10-09 15:00:17 +02:00
|
|
|
except:
|
2017-02-20 19:44:43 +01:00
|
|
|
t,v = sys.exc_info()[:2]
|
2023-05-03 23:49:59 +02:00
|
|
|
test.log("An exception occurred in openDocument(): %s: %s" % (t.__name__, str(v)))
|
2012-10-09 15:00:17 +02:00
|
|
|
return False
|
2013-03-28 16:58:25 +01:00
|
|
|
|
|
|
|
def earlyExit(details="No additional information"):
|
|
|
|
test.fail("Something went wrong running this test", details)
|
2022-12-15 10:54:08 +01:00
|
|
|
saveAndExit()
|
2013-03-28 16:58:25 +01:00
|
|
|
|
|
|
|
def openDocumentPlaceCursor(doc, line, additionalFunction=None):
|
|
|
|
cppEditorStr = ":Qt Creator_CppEditor::Internal::CPPEditorWidget"
|
|
|
|
if openDocument(doc) and placeCursorToLine(cppEditorStr, line):
|
|
|
|
if additionalFunction:
|
|
|
|
additionalFunction()
|
|
|
|
return str(waitForObject(cppEditorStr).plainText)
|
|
|
|
else:
|
|
|
|
earlyExit("Open %s or placing cursor to line (%s) failed." % (doc, line))
|
|
|
|
return None
|
|
|
|
|
|
|
|
# Replaces a line in the editor with another
|
|
|
|
# param fileSpec a string specifying a file in Projects view
|
|
|
|
# param oldLine a string holding the line to be replaced
|
|
|
|
# param newLine a string holding the line to be inserted
|
|
|
|
def replaceLine(fileSpec, oldLine, newLine):
|
|
|
|
if openDocumentPlaceCursor(fileSpec, oldLine) == None:
|
|
|
|
return False
|
|
|
|
editor = waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget")
|
2014-05-22 16:48:35 +02:00
|
|
|
for _ in oldLine:
|
2013-03-28 16:58:25 +01:00
|
|
|
type(editor, "<Backspace>")
|
|
|
|
type(editor, newLine)
|
|
|
|
return True
|
2017-10-13 10:08:08 +02:00
|
|
|
|
|
|
|
def addTestableCodeAfterLine(editorObject, line, newCodeLines):
|
|
|
|
if not placeCursorToLine(editorObject, line):
|
|
|
|
return False
|
|
|
|
type(editorObject, "<Return>")
|
|
|
|
typeLines(editorObject, newCodeLines)
|
|
|
|
return True
|
|
|
|
|
|
|
|
def saveAndExit():
|
|
|
|
invokeMenuItem("File", "Save All")
|
|
|
|
invokeMenuItem("File", "Exit")
|