forked from qt-creator/qt-creator
Squish: Test handling of read only files
Change-Id: I459fdaed7338f5343b760da47e9652baf78986f0 Reviewed-by: Robert Loehning <robert.loehning@digia.com>
This commit is contained in:
@@ -54,6 +54,7 @@
|
|||||||
:Next_QPushButton {text~='(Next.*|Continue)' type='QPushButton' visible='1'}
|
:Next_QPushButton {text~='(Next.*|Continue)' type='QPushButton' visible='1'}
|
||||||
:Open File.File name:_QLabel {name='fileNameLabel' text='File name:' type='QLabel' visible='1' window=':Open File_QFileDialog'}
|
:Open File.File name:_QLabel {name='fileNameLabel' text='File name:' type='QLabel' visible='1' window=':Open File_QFileDialog'}
|
||||||
:Open File_QFileDialog {name='QFileDialog' type='QFileDialog' visible='1' windowTitle='Open File'}
|
:Open File_QFileDialog {name='QFileDialog' type='QFileDialog' visible='1' windowTitle='Open File'}
|
||||||
|
:OpenDocuments_QTreeView {name='editorList' type='QTreeView' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:OpenProject_QStyleItem {clip='false' container=':Qt Creator_QDeclarativeView' enabled='true' text='Open Project' type='LinkedText' unnamed='1' visible='true'}
|
:OpenProject_QStyleItem {clip='false' container=':Qt Creator_QDeclarativeView' enabled='true' text='Open Project' type='LinkedText' unnamed='1' visible='true'}
|
||||||
:Options.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Options_Core::Internal::SettingsDialog'}
|
:Options.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Options_Core::Internal::SettingsDialog'}
|
||||||
:Options.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Options_Core::Internal::SettingsDialog'}
|
:Options.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Options_Core::Internal::SettingsDialog'}
|
||||||
@@ -87,10 +88,12 @@
|
|||||||
:Qt Creator_Core::Internal::CommandComboBox {type='Core::Internal::CommandComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_Core::Internal::CommandComboBox {type='Core::Internal::CommandComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_Core::Internal::MainWindow {type='Core::Internal::MainWindow' visible='1' windowTitle?='*Qt Creator'}
|
:Qt Creator_Core::Internal::MainWindow {type='Core::Internal::MainWindow' visible='1' windowTitle?='*Qt Creator'}
|
||||||
:Qt Creator_CppEditor::Internal::CPPEditorWidget {type='CppEditor::Internal::CPPEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_CppEditor::Internal::CPPEditorWidget {type='CppEditor::Internal::CPPEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
|
:Qt Creator_FilenameQComboBox {type='QComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_Find::Internal::SearchResultTreeView {type='Find::Internal::SearchResultTreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_Find::Internal::SearchResultTreeView {type='Find::Internal::SearchResultTreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_Help::Internal::HelpViewer {type='Help::Internal::HelpViewer' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_Help::Internal::HelpViewer {type='Help::Internal::HelpViewer' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_HelpSelector_QComboBox {occurrence='3' type='QComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_HelpSelector_QComboBox {occurrence='3' type='QComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_Issues_Core::Internal::OutputPaneToggleButton {occurrence='1' type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_Issues_Core::Internal::OutputPaneToggleButton {occurrence='1' type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
|
:Qt Creator_ProFileEditorWidget {type='Qt4ProjectManager::Internal::ProFileEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_QDeclarativeView {type='QDeclarativeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_QDeclarativeView {type='QDeclarativeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_QHelpContentWidget {type='QHelpContentWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_QHelpContentWidget {type='QHelpContentWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
:Qt Creator_QTableView {type='QTableView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
:Qt Creator_QTableView {type='QTableView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
|
||||||
|
@@ -218,13 +218,11 @@ def getEditorForFileSuffix(curFile):
|
|||||||
glslEditorSuffixes= ["frag", "vert", "fsh", "vsh", "glsl", "shader", "gsh"]
|
glslEditorSuffixes= ["frag", "vert", "fsh", "vsh", "glsl", "shader", "gsh"]
|
||||||
suffix = __getFileSuffix__(curFile)
|
suffix = __getFileSuffix__(curFile)
|
||||||
if suffix in cppEditorSuffixes:
|
if suffix in cppEditorSuffixes:
|
||||||
editor = waitForObject("{type='CppEditor::Internal::CPPEditorWidget' unnamed='1' "
|
editor = waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget")
|
||||||
"visible='1' window=':Qt Creator_Core::Internal::MainWindow'}")
|
|
||||||
elif suffix in qmlEditorSuffixes:
|
elif suffix in qmlEditorSuffixes:
|
||||||
editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget")
|
editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget")
|
||||||
elif suffix in proEditorSuffixes:
|
elif suffix in proEditorSuffixes:
|
||||||
editor = waitForObject("{type='Qt4ProjectManager::Internal::ProFileEditorWidget' unnamed='1' "
|
editor = waitForObject(":Qt Creator_ProFileEditorWidget")
|
||||||
"visible='1' window=':Qt Creator_Core::Internal::MainWindow'}")
|
|
||||||
elif suffix in glslEditorSuffixes:
|
elif suffix in glslEditorSuffixes:
|
||||||
editor = waitForObject("{type='GLSLEditor::GLSLTextEditorWidget' unnamed='1' "
|
editor = waitForObject("{type='GLSLEditor::GLSLTextEditorWidget' unnamed='1' "
|
||||||
"visible='1' window=':Qt Creator_Core::Internal::MainWindow'}")
|
"visible='1' window=':Qt Creator_Core::Internal::MainWindow'}")
|
||||||
|
33
tests/system/shared/fs_utils.py
Normal file
33
tests/system/shared/fs_utils.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import stat
|
||||||
|
|
||||||
|
# this function modifies all (regular) files inside the given dirPath to have specified permissions
|
||||||
|
# ATTENTION: it won't process the directory recursively
|
||||||
|
def changeFilePermissions(dirPath, readPerm, writePerm, excludeFileNames=None):
|
||||||
|
permission = 0
|
||||||
|
if readPerm:
|
||||||
|
permission |= stat.S_IREAD
|
||||||
|
if writePerm:
|
||||||
|
permission |= stat.S_IWRITE
|
||||||
|
if excludeFileNames == None:
|
||||||
|
excludeFileNames = []
|
||||||
|
elif isinstance(excludeFileNames, (str, unicode)):
|
||||||
|
excludeFileNames = [excludeFileNames]
|
||||||
|
if not isinstance(excludeFileNames, (tuple, list)):
|
||||||
|
test.warning("File names to exclude must be of type str, unicode, list, tuple or None - "
|
||||||
|
"ignoring parameter this time.")
|
||||||
|
excludeFileNames = []
|
||||||
|
if not os.path.isdir(dirPath):
|
||||||
|
test.warning("Could not find directory '%s'." % dirPath)
|
||||||
|
return False
|
||||||
|
filePaths = [os.path.join(dirPath, fileName) for fileName in os.listdir(dirPath)
|
||||||
|
if fileName not in excludeFileNames]
|
||||||
|
for filePath in filter(os.path.isfile, filePaths):
|
||||||
|
os.chmod(filePath, permission)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def isWritable(pathToFile):
|
||||||
|
if os.path.exists(pathToFile):
|
||||||
|
return os.access(pathToFile, os.W_OK)
|
||||||
|
else:
|
||||||
|
test.warning("Path to check for writability does not exist.")
|
||||||
|
return False
|
@@ -17,6 +17,7 @@ testSettings.logScreenshotOnError = True
|
|||||||
|
|
||||||
source("../../shared/classes.py")
|
source("../../shared/classes.py")
|
||||||
source("../../shared/utils.py")
|
source("../../shared/utils.py")
|
||||||
|
source("../../shared/fs_utils.py")
|
||||||
source("../../shared/build_utils.py")
|
source("../../shared/build_utils.py")
|
||||||
source("../../shared/project.py")
|
source("../../shared/project.py")
|
||||||
source("../../shared/editor_utils.py")
|
source("../../shared/editor_utils.py")
|
||||||
|
@@ -31,8 +31,7 @@ def main():
|
|||||||
# Rely on code completion for closing bracket
|
# Rely on code completion for closing bracket
|
||||||
invokeMenuItem("File", "Save All")
|
invokeMenuItem("File", "Save All")
|
||||||
selectFromLocator(project + ".pro")
|
selectFromLocator(project + ".pro")
|
||||||
proEditor = waitForObject("{type='Qt4ProjectManager::Internal::ProFileEditorWidget' unnamed='1' visible='1'"
|
proEditor = waitForObject(":Qt Creator_ProFileEditorWidget", 20000)
|
||||||
"window=':Qt Creator_Core::Internal::MainWindow'}", 20000)
|
|
||||||
test.verify("CONFIG += console" in str(proEditor.plainText), "Verifying that program is configured with console")
|
test.verify("CONFIG += console" in str(proEditor.plainText), "Verifying that program is configured with console")
|
||||||
setRunInTerminal(1, 0, False)
|
setRunInTerminal(1, 0, False)
|
||||||
|
|
||||||
|
@@ -7,6 +7,6 @@ HOOK_SUB_PROCESSES=false
|
|||||||
IMPLICITAUTSTART=0
|
IMPLICITAUTSTART=0
|
||||||
LANGUAGE=Python
|
LANGUAGE=Python
|
||||||
OBJECTMAP=../objects.map
|
OBJECTMAP=../objects.map
|
||||||
TEST_CASES=tst_memberoperator tst_rename_macros tst_basic_cpp_support tst_select_all tst_qml_indent tst_qml_editor
|
TEST_CASES=tst_basic_cpp_support tst_memberoperator tst_modify_readonly tst_qml_editor tst_qml_indent tst_rename_macros tst_select_all
|
||||||
VERSION=2
|
VERSION=2
|
||||||
WRAPPERS=Qt
|
WRAPPERS=Qt
|
||||||
|
136
tests/system/suite_editors/tst_modify_readonly/test.py
Normal file
136
tests/system/suite_editors/tst_modify_readonly/test.py
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
source("../../shared/qtcreator.py")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global testFolder
|
||||||
|
cppEditorStr = ":Qt Creator_CppEditor::Internal::CPPEditorWidget"
|
||||||
|
proEditorStr = ":Qt Creator_ProFileEditorWidget"
|
||||||
|
testFolder = prepareTemplate(os.path.abspath(os.path.join(os.getcwd(), "..", "shared",
|
||||||
|
"simplePlainCPP")))
|
||||||
|
if testFolder == None:
|
||||||
|
test.fatal("Could not prepare test files - leaving test")
|
||||||
|
return
|
||||||
|
if not changeFilePermissions(testFolder, True, False, "testfiles.pro"):
|
||||||
|
test.fatal("Could not set permissions for files to read-only - test will likely fail.")
|
||||||
|
startApplication("qtcreator" + SettingsPath)
|
||||||
|
openQmakeProject(os.path.join(testFolder, "testfiles.pro"))
|
||||||
|
modifiedUnsaved = []
|
||||||
|
readOnlyFiles = []
|
||||||
|
currentFile = testModifyFile("testfiles.Sources.main\\.cpp", cppEditorStr, "{", True)
|
||||||
|
modifiedUnsaved.append(currentFile)
|
||||||
|
readOnlyFiles.append(currentFile)
|
||||||
|
currentFile = testModifyFile("testfiles.testfiles\\.pro", proEditorStr, "CONFIG -= qt", False)
|
||||||
|
modifiedUnsaved.append(currentFile)
|
||||||
|
currentFile = testModifyFile("testfiles.Headers.testfile\\.h", cppEditorStr, "{", True)
|
||||||
|
modifiedUnsaved.append(currentFile)
|
||||||
|
readOnlyFiles.append(currentFile)
|
||||||
|
invokeMenuItem("File", "Exit")
|
||||||
|
testSaveChangesAndMakeWritable(modifiedUnsaved, readOnlyFiles)
|
||||||
|
|
||||||
|
def testModifyFile(fileName, editor, line, expectWarning):
|
||||||
|
readOnlyWarningStr = ("{text='<b>Warning:</b> You are changing a read-only file.' type='QLabel'"
|
||||||
|
" unnamed='1' window=':Qt Creator_Core::Internal::MainWindow'}")
|
||||||
|
simpleFName = simpleFileName(fileName)
|
||||||
|
test.log("Opening file '%s'" % simpleFName)
|
||||||
|
openDocument(fileName)
|
||||||
|
fileNameCombo = waitForObject(":Qt Creator_FilenameQComboBox")
|
||||||
|
test.compare(str(fileNameCombo.currentText), simpleFName,
|
||||||
|
"Verifying content of file name combo box.")
|
||||||
|
checkOpenDocumentsContains(simpleFName)
|
||||||
|
if not placeCursorToLine(editor, line):
|
||||||
|
return
|
||||||
|
type(editor, "<Return>")
|
||||||
|
try:
|
||||||
|
waitForObject(readOnlyWarningStr, 3000)
|
||||||
|
if expectWarning:
|
||||||
|
test.passes("Warning about changing a read-only file appeared.")
|
||||||
|
else:
|
||||||
|
test.fail("Warning about changing a read-only file appeared, although changing "
|
||||||
|
"a writable file. (%s)" % simpleFName)
|
||||||
|
except:
|
||||||
|
if expectWarning:
|
||||||
|
test.fail("Warning about changing a read-only file missing. (%s)" % simpleFName)
|
||||||
|
else:
|
||||||
|
test.passes("Warning about changing a read-only file does not come up "
|
||||||
|
"(changing a writable file).")
|
||||||
|
test.compare(str(fileNameCombo.currentText), "%s*" % simpleFName,
|
||||||
|
"Verifying content of file name combo box.")
|
||||||
|
return checkOpenDocumentsContains("%s*" % simpleFName)
|
||||||
|
|
||||||
|
def testSaveChangesAndMakeWritable(modifiedFiles, readOnlyFiles):
|
||||||
|
saveDlgStr = ("{name='Core__Internal__SaveItemsDialog' type='Core::Internal::SaveItemsDialog' "
|
||||||
|
"visible='1' windowTitle='Save Changes'}")
|
||||||
|
readOnlyMBoxStr = ("{type='QMessageBox' unnamed='1' visible='1' text~='The file <i>.+</i> "
|
||||||
|
"is read only\.'}")
|
||||||
|
cannotResetStr = ("{text='Cannot set permissions to writable.' type='QMessageBox' "
|
||||||
|
"unnamed='1' visible='1'}")
|
||||||
|
filePattern = re.compile('The file <i>(.+)</i> is read only\.')
|
||||||
|
try:
|
||||||
|
waitForObject(saveDlgStr)
|
||||||
|
except:
|
||||||
|
test.fail("Save Changes dialog did not come up, but was expected to appear.")
|
||||||
|
return
|
||||||
|
treeWidget = waitForObject("{name='treeWidget' type='QTreeWidget' visible='1' window=%s}"
|
||||||
|
% saveDlgStr)
|
||||||
|
checkUnsavedChangesContains(treeWidget.model(), modifiedFiles)
|
||||||
|
clickButton(waitForObject("{text='Save All' type='QPushButton' unnamed='1' visible='1' "
|
||||||
|
"window=%s}" % saveDlgStr))
|
||||||
|
# iterating over the readOnlyFiles (order is unpredictable)
|
||||||
|
for i in range(len(readOnlyFiles)):
|
||||||
|
try:
|
||||||
|
currentText = str(waitForObject(readOnlyMBoxStr, 3000).text)
|
||||||
|
currentFile = filePattern.match(currentText).group(1)
|
||||||
|
clickButton(waitForObject("{text='Make Writable' type='QPushButton' unnamed='1' "
|
||||||
|
"visible='1' window=%s}" % readOnlyMBoxStr))
|
||||||
|
try:
|
||||||
|
waitForObject(cannotResetStr, 3000)
|
||||||
|
# should not be possible
|
||||||
|
test.fail("Could not reset file '%s' to writable state." % currentFile)
|
||||||
|
clickButton("{text='OK' type='QPushButton' window=%s}" % cannotResetStr)
|
||||||
|
except:
|
||||||
|
if isWritable(currentFile):
|
||||||
|
test.passes("File '%s' resetted to writable state and saved." % currentFile)
|
||||||
|
if currentFile in readOnlyFiles:
|
||||||
|
readOnlyFiles.remove(currentFile)
|
||||||
|
else:
|
||||||
|
test.fatal("Creator states file '%s' is read-only - but supposed to be "
|
||||||
|
"writable." % currentFile)
|
||||||
|
else:
|
||||||
|
test.fail("Creator states file '%s' had been made writable - "
|
||||||
|
"but it's still read only." % currentFile)
|
||||||
|
except:
|
||||||
|
test.fail("Missing QMessageBox about a read only file.")
|
||||||
|
if not test.verify(len(readOnlyFiles) == 0,
|
||||||
|
"Checking whether all files have been handled correctly."):
|
||||||
|
try:
|
||||||
|
invokeMenuItem("File", "Exit")
|
||||||
|
waitForObject(saveDlgStr)
|
||||||
|
clickButton(waitForObject("{text='Do not Save' type='QPushButton' unnamed='1' "
|
||||||
|
"visible='1' window=%s}" % saveDlgStr))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def checkOpenDocumentsContains(itemName):
|
||||||
|
openDocsTreeViewModel = waitForObject(":OpenDocuments_QTreeView").model()
|
||||||
|
result = None
|
||||||
|
found = False
|
||||||
|
for index in dumpIndices(openDocsTreeViewModel):
|
||||||
|
if str(index.data()) == itemName:
|
||||||
|
found = True
|
||||||
|
result = index.toolTip
|
||||||
|
break
|
||||||
|
test.verify(found, "Check whether 'Open Documents' contains '%s'" % itemName)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def checkUnsavedChangesContains(model, filePaths):
|
||||||
|
foundItems = map(lambda x: os.path.join(x[0], x[1]), zip(dumpItems(model,column=1),
|
||||||
|
dumpItems(model, column=0)))
|
||||||
|
test.compare(set(foundItems), set(filePaths),
|
||||||
|
"Verifying whether modified (unsaved) files do match expected.")
|
||||||
|
|
||||||
|
def simpleFileName(navigatorFileName):
|
||||||
|
return ".".join(navigatorFileName.split(".")[-2:]).replace("\\","")
|
||||||
|
|
||||||
|
def cleanup():
|
||||||
|
global testFolder
|
||||||
|
if testFolder:
|
||||||
|
changeFilePermissions(testFolder, True, True, "testfiles.pro")
|
Reference in New Issue
Block a user