Address failing test case for internal implementation of moveToTrash

This ammends 601ce9e08aa92b273f1a6daf0bdbc67dbf9b4e5f, which added
a new test case for the internal Qt APIs. The test was not
getting executed by coin as it wasn't included in the io.pro file,
and trying to fix that generates link errors on Windows, since these
internal APIs depend on other internal APIs.

Short of bootstrapping much of QtCore into this test case, the only
sensible option is to remove this test case again, and cover the
testing when the public API is added in a follow up commit.

At the same time, address those failures that were discovered
on platforms that could build the test, and fix compilation on
iOS platforms in Coin.

Change-Id: Id31b43c9df9f205476c48bccb6b87c7a53ed15c5
Reviewed-by: Vitaly Fanaskov <vitaly.fanaskov@qt.io>
This commit is contained in:
Volker Hilsheimer 2020-01-31 12:54:17 +01:00
parent 6b858e21ed
commit 336b3bb0dd
4 changed files with 30 additions and 192 deletions

View File

@ -60,20 +60,24 @@ QT_BEGIN_NAMESPACE
bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
QFileSystemEntry &newLocation, QSystemError &error)
{
#ifdef Q_OS_MACOS // desktop macOS has a trash can
QMacAutoReleasePool pool;
QFileInfo info(source.filePath());
@autoreleasepool {
NSString *filepath = info.filePath().toNSString();
NSURL *fileurl = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
NSURL *resultingUrl = nil;
NSError *nserror = nil;
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm trashItemAtURL:fileurl resultingItemURL:&resultingUrl error:&nserror] != YES) {
error = QSystemError(nserror.code, QSystemError::NativeError);
return false;
}
newLocation = QFileSystemEntry(QUrl::fromNSURL(resultingUrl).path());
NSString *filepath = info.filePath().toNSString();
NSURL *fileurl = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
NSURL *resultingUrl = nil;
NSError *nserror = nil;
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm trashItemAtURL:fileurl resultingItemURL:&resultingUrl error:&nserror] != YES) {
error = QSystemError(nserror.code, QSystemError::NativeError);
return false;
}
newLocation = QFileSystemEntry(QUrl::fromNSURL(resultingUrl).path());
return true;
#else // watch, tv, iOS don't have a trash can
return false;
#endif
}
QT_END_NAMESPACE

View File

@ -1341,13 +1341,15 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
QString infoFileName;
int counter = 0;
QFile infoFile;
do {
while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName)) {
++counter;
uniqueTrashedName = QString(QLatin1String("/%1-%2"))
auto makeUniqueTrashedName = [trashedName, &counter]() -> QString {
++counter;
return QString(QLatin1String("/%1-%2"))
.arg(trashedName)
.arg(counter, 4, 10, QLatin1Char('0'));
}
};
do {
while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName))
uniqueTrashedName = makeUniqueTrashedName();
/*
"The $trash/info directory contains an "information file" for every file and directory
in $trash/files. This file MUST have exactly the same name as the file or directory in
@ -1363,15 +1365,21 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
infoFileName = trashDir.filePath(infoDir)
+ uniqueTrashedName + QLatin1String(".trashinfo");
infoFile.setFileName(infoFileName);
} while (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text));
if (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text))
uniqueTrashedName = makeUniqueTrashedName();
} while (!infoFile.isOpen());
const QString targetPath = trashDir.filePath(filesDir) + uniqueTrashedName;
const QFileSystemEntry target(targetPath);
/*
We might fail to rename if source and target are on different file systems.
In that case, we don't try further, i.e. copying and removing the original
is usually not what the user would expect to happen.
*/
if (!renameFile(source, target, error)) {
infoFile.close();
infoFile.remove();
error = QSystemError(errno, QSystemError::StandardLibraryError);
return false;
}

View File

@ -1,6 +0,0 @@
CONFIG += testcase
TARGET = tst_qfilesystemengine
QT = core-private testlib
SOURCES = tst_qfilesystemengine.cpp \
$$QT_SOURCE_TREE/src/corelib/io/qfilesystementry.cpp
HEADERS = $$QT_SOURCE_TREE/src/corelib/io/qfilesystementry_p.h

View File

@ -1,168 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QtCore/QTemporaryDir>
#include <QtCore/QTemporaryFile>
#include <QtCore/private/qfilesystementry_p.h>
#include <QtCore/private/qfilesystemengine_p.h>
class tst_QFileSystemEngine : public QObject
{
Q_OBJECT
private slots:
void cleanupTestCase();
void moveToTrash_data();
void moveToTrash();
private:
QStringList createdEntries;
};
void tst_QFileSystemEngine::cleanupTestCase()
{
for (QString entry : createdEntries) {
QFileInfo entryInfo(entry);
if (!entryInfo.exists())
continue;
QDir entryDir(entry);
if (entryInfo.isDir()) {
if (!entryDir.removeRecursively())
qWarning("Failed to remove trashed dir '%s'", entry.toLocal8Bit().constData());
} else if (!QFile::remove(entry)) {
qWarning("Failed to remove trashed file '%s'", entry.toLocal8Bit().constData());
}
}
}
void tst_QFileSystemEngine::moveToTrash_data()
{
QTest::addColumn<QString>("filePath");
QTest::addColumn<bool>("create");
QTest::addColumn<bool>("success");
{
QTemporaryFile tempFile;
tempFile.open();
QTest::newRow("temporary file")
<< tempFile.fileName()
<< true << true;
}
{
QTemporaryDir tempDir;
tempDir.setAutoRemove(false);
QTest::newRow("temporary dir")
<< tempDir.path() + QLatin1Char('/')
<< true << true;
}
{
QTemporaryDir homeDir(QFileSystemEngine::homePath() + QLatin1String("/XXXXXX"));
homeDir.setAutoRemove(false);
QTemporaryFile homeFile(homeDir.path()
+ QLatin1String("/tst_qfilesystemengine-XXXXXX"));
homeFile.open();
QTest::newRow("home file")
<< homeFile.fileName()
<< true << true;
QTest::newRow("home dir")
<< homeDir.path() + QLatin1Char('/')
<< true << true;
}
QTest::newRow("unmovable")
<< QFileSystemEngine::rootPath()
<< false << false;
QTest::newRow("no such file")
<< QString::fromLatin1("no/such/file")
<< false << false;
}
void tst_QFileSystemEngine::moveToTrash()
{
QFETCH(QString, filePath);
QFETCH(bool, create);
QFETCH(bool, success);
#if defined(Q_OS_WINRT)
QSKIP("WinRT does not have a trash", SkipAll);
#endif
if (create && !QFileInfo::exists(filePath)) {
createdEntries << filePath;
if (filePath.endsWith(QLatin1Char('/'))) {
QDir temp(QFileSystemEngine::rootPath());
temp.mkdir(filePath);
QFile file(filePath + QLatin1String("test"));
if (!file.open(QIODevice::WriteOnly))
QSKIP("Couldn't create directory with file");
} else {
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly))
QSKIP("Couldn't open file for writing");
}
QVERIFY(QFileInfo::exists(filePath));
}
QFileSystemEntry entry(filePath);
QFileSystemEntry newLocation;
QSystemError error;
bool existed = QFileInfo::exists(filePath);
bool result = QFileSystemEngine::moveFileToTrash(entry, newLocation, error);
QCOMPARE(result, success);
if (result) {
QCOMPARE(error.error(), 0);
QVERIFY(existed != QFileInfo::exists(filePath));
const QString newPath = newLocation.filePath();
#if defined(Q_OS_WIN)
// one of the Windows code paths doesn't provide the location of the object in the trash
if (newPath.isEmpty())
QEXPECT_FAIL("", "Qt built without IFileOperations support on Windows!", Continue);
#endif
QVERIFY(!newPath.isEmpty());
if (!newPath.isEmpty()) {
createdEntries << newPath;
QFileInfo trashInfo(newPath);
QVERIFY(trashInfo.exists());
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
QString infoFile = trashInfo.absolutePath() + QLatin1String("/../info/")
+ trashInfo.fileName() + QLatin1String(".trashinfo");
createdEntries << infoFile;
#endif
}
} else {
QVERIFY(error.error() != 0);
QCOMPARE(existed, QFileInfo::exists(filePath));
}
}
QTEST_MAIN(tst_QFileSystemEngine)
#include <tst_qfilesystemengine.moc>