Merge pull request #4454 from nextcloud/bugfix/allow-manual-rename-files-with-spaces

Bugfix/allow manual rename files with spaces
This commit is contained in:
allexzander 2022-05-16 18:08:15 +03:00 committed by GitHub
commit fc8bfdc9f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 401 additions and 261 deletions

View File

@ -165,9 +165,7 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const QString &path, bool exclu
// as '.' is a separator that is not stored internally, so let's
// not allow to sync those to avoid file loss/ambiguities (#416)
if (blen > 1) {
if (bname.at(blen - 1) == QLatin1Char(' ')) {
return CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
} else if (bname.at(blen - 1) == QLatin1Char('.')) {
if (bname.at(blen - 1) == QLatin1Char('.')) {
return CSYNC_FILE_EXCLUDE_INVALID_CHAR;
}
}

View File

@ -45,6 +45,8 @@ enum CSYNC_EXCLUDE_TYPE {
CSYNC_FILE_EXCLUDE_CONFLICT,
CSYNC_FILE_EXCLUDE_CANNOT_ENCODE,
CSYNC_FILE_EXCLUDE_SERVER_BLACKLISTED,
CSYNC_FILE_EXCLUDE_LEADING_SPACE,
CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE,
};
class ExcludedFilesTest;

View File

@ -1225,6 +1225,11 @@ void Folder::scheduleThisFolderSoon()
}
}
void Folder::acceptInvalidFileName(const QString &filePath)
{
_engine->addAcceptedInvalidFileName(filePath);
}
void Folder::setSaveBackwardsCompatible(bool save)
{
_saveBackwardsCompatible = save;

View File

@ -256,6 +256,8 @@ public:
*/
void scheduleThisFolderSoon();
void acceptInvalidFileName(const QString &filePath);
/**
* Migration: When this flag is true, this folder will save to
* the backwards-compatible 'Folders' section in the config file.

View File

@ -18,6 +18,7 @@
#include "propagateremotemove.h"
#include "ui_invalidfilenamedialog.h"
#include "filesystem.h"
#include <folder.h>
#include <QPushButton>
@ -84,13 +85,18 @@ InvalidFilenameDialog::InvalidFilenameDialog(AccountPtr account, Folder *folder,
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Rename file"));
_ui->descriptionLabel->setText(tr("The file %1 could not be synced because the name contains characters which are not allowed on this system.").arg(_originalFileName));
_ui->explanationLabel->setText(tr("The following characters are not allowed on the system: * \" | & ? , ; : \\ / ~ < >"));
_ui->descriptionLabel->setText(tr("The file \"%1\" could not be synced because the name contains characters which are not allowed on this system.").arg(_originalFileName));
_ui->explanationLabel->setText(tr("The following characters are not allowed on the system: * \" | & ? , ; : \\ / ~ < > leading/trailing spaces"));
_ui->filenameLineEdit->setText(filePathFileInfo.fileName());
connect(_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
_ui->errorLabel->setText(
tr("Checking rename permissions..."));
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
_ui->filenameLineEdit->setEnabled(false);
connect(_ui->filenameLineEdit, &QLineEdit::textChanged, this,
&InvalidFilenameDialog::onFilenameLineEditTextChanged);
@ -104,30 +110,88 @@ void InvalidFilenameDialog::checkIfAllowedToRename()
const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _originalFileName));
propfindJob->setProperties({ "http://owncloud.org/ns:permissions" });
connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onPropfindPermissionSuccess);
connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onPropfindPermissionError);
propfindJob->start();
}
void InvalidFilenameDialog::onCheckIfAllowedToRenameComplete(const QVariantMap &values, QNetworkReply *reply)
{
const auto isAllowedToRename = [](const RemotePermissions remotePermissions) {
return remotePermissions.hasPermission(remotePermissions.CanRename)
&& remotePermissions.hasPermission(remotePermissions.CanMove);
};
if (values.contains("permissions") && !isAllowedToRename(RemotePermissions::fromServerString(values["permissions"].toString()))) {
_ui->errorLabel->setText(
tr("You don't have the permission to rename this file. Please ask the author of the file to rename it."));
return;
} else if (reply) {
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 404) {
_ui->errorLabel->setText(
tr("Failed to fetch permissions with error %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()));
return;
}
}
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
_ui->filenameLineEdit->setEnabled(true);
_ui->filenameLineEdit->selectAll();
const auto filePathFileInfo = QFileInfo(_filePath);
const auto fileName = filePathFileInfo.fileName();
processLeadingOrTrailingSpacesError(fileName);
}
bool InvalidFilenameDialog::processLeadingOrTrailingSpacesError(const QString &fileName)
{
const auto hasLeadingSpaces = fileName.startsWith(QLatin1Char(' '));
const auto hasTrailingSpaces = fileName.endsWith(QLatin1Char(' '));
_ui->buttonBox->setStandardButtons(_ui->buttonBox->standardButtons() &~ QDialogButtonBox::No);
if (hasLeadingSpaces || hasTrailingSpaces) {
if (hasLeadingSpaces && hasTrailingSpaces) {
_ui->errorLabel->setText(tr("Filename contains leading and trailing spaces."));
}
else if (hasLeadingSpaces) {
_ui->errorLabel->setText(tr("Filename contains leading spaces."));
} else if (hasTrailingSpaces) {
_ui->errorLabel->setText(tr("Filename contains trailing spaces."));
}
if (!Utility::isWindows()) {
_ui->buttonBox->setStandardButtons(_ui->buttonBox->standardButtons() | QDialogButtonBox::No);
_ui->buttonBox->button(QDialogButtonBox::No)->setText(tr("Use invalid name"));
connect(_ui->buttonBox->button(QDialogButtonBox::No), &QPushButton::clicked, this, &InvalidFilenameDialog::useInvalidName);
}
return true;
}
return false;
}
void InvalidFilenameDialog::onPropfindPermissionSuccess(const QVariantMap &values)
{
if (!values.contains("permissions")) {
return;
}
const auto remotePermissions = RemotePermissions::fromServerString(values["permissions"].toString());
if (!remotePermissions.hasPermission(remotePermissions.CanRename)
|| !remotePermissions.hasPermission(remotePermissions.CanMove)) {
_ui->errorLabel->setText(
tr("You don't have the permission to rename this file. Please ask the author of the file to rename it."));
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
_ui->filenameLineEdit->setEnabled(false);
}
onCheckIfAllowedToRenameComplete(values);
}
void InvalidFilenameDialog::onPropfindPermissionError(QNetworkReply *reply)
{
onCheckIfAllowedToRenameComplete({}, reply);
}
void InvalidFilenameDialog::useInvalidName()
{
emit acceptedInvalidName(_filePath);
}
void InvalidFilenameDialog::accept()
{
_newFilename = _relativeFilePath + _ui->filenameLineEdit->text().trimmed();
const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _newFilename));
connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onRemoteFileAlreadyExists);
connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onRemoteFileDoesNotExist);
connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onRemoteDestinationFileAlreadyExists);
connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onRemoteDestinationFileDoesNotExist);
propfindJob->start();
}
@ -138,11 +202,10 @@ void InvalidFilenameDialog::onFilenameLineEditTextChanged(const QString &text)
const auto containsIllegalChars = !illegalContainedCharacters.empty() || text.endsWith(QLatin1Char('.'));
const auto isTextValid = isNewFileNameDifferent && !containsIllegalChars;
if (isTextValid) {
_ui->errorLabel->setText("");
} else {
_ui->errorLabel->setText(tr("Filename contains illegal characters: %1")
.arg(illegalCharacterListToString(illegalContainedCharacters)));
_ui->errorLabel->setText("");
if (!processLeadingOrTrailingSpacesError(text) && !isTextValid){
_ui->errorLabel->setText(tr("Filename contains illegal characters: %1").arg(illegalCharacterListToString(illegalContainedCharacters)));
}
_ui->buttonBox->button(QDialogButtonBox::Ok)
@ -162,7 +225,7 @@ void InvalidFilenameDialog::onMoveJobFinished()
QDialog::accept();
}
void InvalidFilenameDialog::onRemoteFileAlreadyExists(const QVariantMap &values)
void InvalidFilenameDialog::onRemoteDestinationFileAlreadyExists(const QVariantMap &values)
{
Q_UNUSED(values);
@ -170,15 +233,41 @@ void InvalidFilenameDialog::onRemoteFileAlreadyExists(const QVariantMap &values)
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
}
void InvalidFilenameDialog::onRemoteFileDoesNotExist(QNetworkReply *reply)
void InvalidFilenameDialog::onRemoteDestinationFileDoesNotExist(QNetworkReply *reply)
{
Q_UNUSED(reply);
// File does not exist. We can rename it.
const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _originalFileName));
connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onRemoteSourceFileAlreadyExists);
connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onRemoteSourceFileDoesNotExist);
propfindJob->start();
}
void InvalidFilenameDialog::onRemoteSourceFileAlreadyExists(const QVariantMap &values)
{
Q_UNUSED(values);
// Remote source file exists. We need to start MoveJob to rename it
const auto remoteSource = QDir::cleanPath(_folder->remotePath() + _originalFileName);
const auto remoteDestionation = QDir::cleanPath(_account->davUrl().path() + _folder->remotePath() + _newFilename);
const auto moveJob = new MoveJob(_account, remoteSource, remoteDestionation, this);
connect(moveJob, &MoveJob::finishedSignal, this, &InvalidFilenameDialog::onMoveJobFinished);
moveJob->start();
}
void InvalidFilenameDialog::onRemoteSourceFileDoesNotExist(QNetworkReply *reply)
{
Q_UNUSED(reply);
// It's a new file we've just created locally. We will attempt to rename it locally.
const auto localSource = QDir::cleanPath(_folder->path() + _originalFileName);
const auto localDestionation = QDir::cleanPath(_folder->path()+ _newFilename);
QString error;
if (!FileSystem::rename(localSource, localDestionation, &error)) {
_ui->errorLabel->setText(tr("Could not rename local file. %1").arg(error));
return;
}
QDialog::accept();
}
}

View File

@ -41,6 +41,9 @@ public:
void accept() override;
signals:
void acceptedInvalidName(const QString &filePath);
private:
std::unique_ptr<Ui::InvalidFilenameDialog> _ui;
@ -53,9 +56,16 @@ private:
void onFilenameLineEditTextChanged(const QString &text);
void onMoveJobFinished();
void onRemoteFileAlreadyExists(const QVariantMap &values);
void onRemoteFileDoesNotExist(QNetworkReply *reply);
void onRemoteDestinationFileAlreadyExists(const QVariantMap &values);
void onRemoteDestinationFileDoesNotExist(QNetworkReply *reply);
void onRemoteSourceFileAlreadyExists(const QVariantMap &values);
void onRemoteSourceFileDoesNotExist(QNetworkReply *reply);
void checkIfAllowedToRename();
void onCheckIfAllowedToRenameComplete(const QVariantMap &values, QNetworkReply *reply = nullptr);
bool processLeadingOrTrailingSpacesError(const QString &fileName);
void onPropfindPermissionSuccess(const QVariantMap &values);
void onPropfindPermissionError(QNetworkReply *reply = nullptr);
private slots:
void useInvalidName();
};
}

View File

@ -688,6 +688,10 @@ void ActivityListModel::slotTriggerDefaultAction(const int activityIndex)
connect(_currentInvalidFilenameDialog, &InvalidFilenameDialog::accepted, folder, [folder]() {
folder->scheduleThisFolderSoon();
});
connect(_currentInvalidFilenameDialog, &InvalidFilenameDialog::acceptedInvalidName, folder, [folder](const QString& filePath) {
folder->acceptInvalidFileName(filePath);
folder->scheduleThisFolderSoon();
});
_currentInvalidFilenameDialog->open();
ownCloudGui::raiseDialog(_currentInvalidFilenameDialog);
return;

View File

@ -37,54 +37,6 @@ namespace OCC {
Q_LOGGING_CATEGORY(lcDisco, "sync.discovery", QtInfoMsg)
bool ProcessDirectoryJob::checkForInvalidFileName(const PathTuple &path,
const std::map<QString, Entries> &entries, Entries &entry)
{
const auto originalFileName = entry.localEntry.isValid() ? entry.localEntry.name : entry.serverEntry.name;
const auto newFileName = originalFileName.trimmed();
if (originalFileName == newFileName) {
return true;
}
const auto entriesIter = entries.find(newFileName);
if (entriesIter != entries.end()) {
QString errorMessage;
const auto newFileNameEntry = entriesIter->second;
if (entry.serverEntry.isValid() && newFileNameEntry.serverEntry.isValid()) {
errorMessage = tr("File contains trailing spaces and could not be renamed, because a file with the same name already exists on the server.");
}
if (entry.localEntry.isValid() && newFileNameEntry.localEntry.isValid()) {
errorMessage = tr("File contains trailing spaces and could not be renamed, because a file with the same name already exists locally.");
}
if (!errorMessage.isEmpty()) {
auto item = SyncFileItemPtr::create();
if ((entry.localEntry.isValid() && entry.localEntry.isDirectory) || (entry.serverEntry.isValid() && entry.serverEntry.isDirectory)) {
item->_type = CSyncEnums::ItemTypeDirectory;
} else {
item->_type = CSyncEnums::ItemTypeFile;
}
item->_file = path._target;
item->_originalFile = path._target;
item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_status = SyncFileItem::NormalError;
item->_errorString = errorMessage;
processFileFinalize(item, path, false, ParentNotChanged, ParentNotChanged);
return false;
}
}
if (entry.localEntry.isValid()) {
entry.localEntry.renameName = newFileName;
} else {
entry.serverEntry.renameName = newFileName;
}
return true;
}
void ProcessDirectoryJob::start()
{
qCInfo(lcDisco) << "STARTING" << _currentFolder._server << _queryServer << _currentFolder._local << _queryLocal;
@ -222,33 +174,46 @@ void ProcessDirectoryJob::process()
// local stat function.
// Recall file shall not be ignored (#4420)
bool isHidden = e.localEntry.isHidden || (!f.first.isEmpty() && f.first[0] == '.' && f.first != QLatin1String(".sys.admin#recall#"));
#ifdef Q_OS_WIN
// exclude ".lnk" files as they are not essential, but, causing troubles when enabling the VFS due to QFileInfo::isDir() and other methods are freezing, which causes the ".lnk" files to start hydrating and freezing the app eventually.
const bool isServerEntryWindowsShortcut = !e.localEntry.isValid() && e.serverEntry.isValid() && !e.serverEntry.isDirectory && FileSystem::isLnkFile(e.serverEntry.name);
#else
const bool isServerEntryWindowsShortcut = false;
#endif
if (handleExcluded(path._target, e.localEntry.name,
e.localEntry.isDirectory || e.serverEntry.isDirectory, isHidden,
e.localEntry.isSymLink || isServerEntryWindowsShortcut))
if (handleExcluded(path._target, e, isHidden))
continue;
if (_queryServer == InBlackList || _discoveryData->isInSelectiveSyncBlackList(path._original)) {
processBlacklisted(path, e.localEntry, e.dbEntry);
continue;
}
if (!checkForInvalidFileName(path, entries, e)) {
continue;
}
processFile(std::move(path), e.localEntry, e.serverEntry, e.dbEntry);
}
QTimer::singleShot(0, _discoveryData, &DiscoveryPhase::scheduleMoreJobs);
}
bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &localName, bool isDirectory, bool isHidden, bool isSymlink)
bool ProcessDirectoryJob::handleExcluded(const QString &path, const Entries &entries, bool isHidden)
{
const auto isDirectory = entries.localEntry.isDirectory || entries.serverEntry.isDirectory;
auto excluded = _discoveryData->_excludes->traversalPatternMatch(path, isDirectory ? ItemTypeDirectory : ItemTypeFile);
const auto fileName = path.mid(path.lastIndexOf('/') + 1);
if (excluded == CSYNC_NOT_EXCLUDED) {
const auto endsWithSpace = fileName.endsWith(QLatin1Char(' '));
const auto startsWithSpace = fileName.startsWith(QLatin1Char(' '));
if (startsWithSpace && endsWithSpace) {
excluded = CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE;
} else if (endsWithSpace) {
excluded = CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
} else if (startsWithSpace) {
excluded = CSYNC_FILE_EXCLUDE_LEADING_SPACE;
}
}
// we don't need to trigger a warning if trailing/leading space file is already on the server or has already been synced down
// only if the OS supports trailing/leading spaces
const auto wasSyncedAlreadyAndOsSupportsSpaces = !Utility::isWindows() && (entries.serverEntry.isValid() || entries.dbEntry.isValid());
if ((excluded == CSYNC_FILE_EXCLUDE_LEADING_SPACE || excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE || excluded == CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE)
&& (wasSyncedAlreadyAndOsSupportsSpaces || _discoveryData->_leadingAndTrailingSpacesFilesAllowed.contains(_discoveryData->_localDir + path))) {
excluded = CSYNC_NOT_EXCLUDED;
}
// FIXME: move to ExcludedFiles 's regexp ?
bool isInvalidPattern = false;
if (excluded == CSYNC_NOT_EXCLUDED && !_discoveryData->_invalidFilenameRx.pattern().isEmpty()) {
@ -260,6 +225,8 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &loc
if (excluded == CSYNC_NOT_EXCLUDED && _discoveryData->_ignoreHiddenFiles && isHidden) {
excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
}
const auto &localName = entries.localEntry.name;
if (excluded == CSYNC_NOT_EXCLUDED && !localName.isEmpty()
&& _discoveryData->_serverBlacklistedFiles.contains(localName)) {
excluded = CSYNC_FILE_EXCLUDE_SERVER_BLACKLISTED;
@ -280,6 +247,17 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &loc
}
}
#ifdef Q_OS_WIN
// exclude ".lnk" files as they are not essential, but, causing troubles when enabling the VFS due to
// QFileInfo::isDir() and other methods are freezing, which causes the ".lnk" files to start hydrating and freezing
// the app eventually.
const bool isServerEntryWindowsShortcut = !entries.localEntry.isValid() && entries.serverEntry.isValid()
&& !entries.serverEntry.isDirectory && FileSystem::isLnkFile(entries.serverEntry.name);
#else
const bool isServerEntryWindowsShortcut = false;
#endif
const auto isSymlink = entries.localEntry.isSymLink || isServerEntryWindowsShortcut;
if (excluded == CSYNC_NOT_EXCLUDED && !isSymlink) {
return false;
} else if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED || excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
@ -329,6 +307,14 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &loc
item->_errorString = tr("Filename contains trailing spaces.");
item->_status = SyncFileItem::FileNameInvalid;
break;
case CSYNC_FILE_EXCLUDE_LEADING_SPACE:
item->_errorString = tr("Filename contains leading spaces.");
item->_status = SyncFileItem::FileNameInvalid;
break;
case CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE:
item->_errorString = tr("Filename contains leading and trailing spaces.");
item->_status = SyncFileItem::FileNameInvalid;
break;
case CSYNC_FILE_EXCLUDE_LONG_FILENAME:
item->_errorString = tr("Filename is too long.");
item->_status = SyncFileItem::FileNameInvalid;

View File

@ -150,8 +150,6 @@ private:
}
};
bool checkForInvalidFileName(const PathTuple &path, const std::map<QString, Entries> &entries, Entries &entry);
/** Iterate over entries inside the directory (non-recursively).
*
* Called once _serverEntries and _localEntries are filled
@ -162,8 +160,7 @@ private:
// return true if the file is excluded.
// path is the full relative path of the file. localName is the base name of the local entry.
bool handleExcluded(const QString &path, const QString &localName, bool isDirectory,
bool isHidden, bool isSymlink);
bool handleExcluded(const QString &path, const Entries &entries, bool isHidden);
/** Reconcile local/remote/db information for a single item.
*

View File

@ -271,6 +271,7 @@ public:
ExcludedFiles *_excludes;
QRegularExpression _invalidFilenameRx; // FIXME: maybe move in ExcludedFiles
QStringList _serverBlacklistedFiles; // The blacklist from the capabilities
QStringList _leadingAndTrailingSpacesFilesAllowed;
bool _ignoreHiddenFiles = false;
std::function<bool(const QString &)> _shouldDiscoverLocaly;

View File

@ -548,6 +548,7 @@ void SyncEngine::startSync()
emit transmissionProgress(*_progressInfo);
_discoveryPhase.reset(new DiscoveryPhase);
_discoveryPhase->_leadingAndTrailingSpacesFilesAllowed = _leadingAndTrailingSpacesFilesAllowed;
_discoveryPhase->_account = _account;
_discoveryPhase->_excludes = _excludedFiles.data();
const QString excludeFilePath = _localPath + QStringLiteral(".sync-exclude.lst");
@ -852,6 +853,7 @@ void SyncEngine::finalize(bool success)
_localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
_clearTouchedFilesTimer.start();
_leadingAndTrailingSpacesFilesAllowed.clear();
}
void SyncEngine::slotProgress(const SyncFileItem &item, qint64 current)
@ -924,6 +926,11 @@ void SyncEngine::slotClearTouchedFiles()
_touchedFiles.clear();
}
void SyncEngine::addAcceptedInvalidFileName(const QString& filePath)
{
_leadingAndTrailingSpacesFilesAllowed.append(filePath);
}
bool SyncEngine::wasFileTouched(const QString &fn) const
{
// Start from the end (most recent) and look for our path. Check the time just in case.

View File

@ -74,6 +74,8 @@ public:
bool ignoreHiddenFiles() const { return _ignore_hidden_files; }
void setIgnoreHiddenFiles(bool ignore) { _ignore_hidden_files = ignore; }
void addAcceptedInvalidFileName(const QString& filePath);
ExcludedFiles &excludedFiles() { return *_excludedFiles; }
Utility::StopWatch &stopWatch() { return _stopWatch; }
SyncFileStatusTracker &syncFileStatusTracker() { return *_syncFileStatusTracker; }
@ -295,6 +297,8 @@ private:
LocalDiscoveryStyle _lastLocalDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
LocalDiscoveryStyle _localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
std::set<QString> _localDiscoveryPaths;
QStringList _leadingAndTrailingSpacesFilesAllowed;
};
}

View File

@ -141,7 +141,7 @@ void SyncResult::processCompletedItem(const SyncFileItemPtr &item)
if (!_firstItemError) {
_firstItemError = item;
}
} else if (item->_status == SyncFileItem::Conflict) {
} else if (item->_status == SyncFileItem::Conflict || item->_status == SyncFileItem::FileNameInvalid) {
if (item->_instruction == CSYNC_INSTRUCTION_CONFLICT) {
_numNewConflictItems++;
if (!_firstNewConflictItem) {

View File

@ -210,10 +210,10 @@ private slots:
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces1(" foo");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
const QString fileWithSpaces4("A/ foo");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
fakeFolder.localModifier().insert(fileWithSpaces1);
@ -223,76 +223,50 @@ private slots:
fakeFolder.localModifier().insert(fileWithSpaces4);
fakeFolder.localModifier().insert(fileWithSpaces5);
fakeFolder.localModifier().insert(fileWithSpaces6);
fakeFolder.localModifier().mkdir(QStringLiteral(" with spaces "));
fakeFolder.localModifier().mkdir(QStringLiteral(" with spaces "));
ItemCompletedSpy completeSpy(fakeFolder);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(QStringLiteral(" with spaces "))->_status, SyncFileItem::Status::FileNameInvalid);
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces1);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces2);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces3);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces4);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces5);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces6);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + QStringLiteral(" with spaces "));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
QVERIFY(fakeFolder.currentLocalState().find(QStringLiteral("with spaces")));
QVERIFY(!fakeFolder.currentLocalState().find(QStringLiteral(" with spaces ")));
completeSpy.clear();
fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, {QStringLiteral("foo"), QStringLiteral("bar"), QStringLiteral("bla"), QStringLiteral("A/foo"), QStringLiteral("A/bar"), QStringLiteral("A/bla")});
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces1.trimmed()));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces1));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces2.trimmed()));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces2));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces3.trimmed()));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces3));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
QVERIFY(fakeFolder.currentRemoteState().find(QStringLiteral("with spaces")));
QVERIFY(!fakeFolder.currentRemoteState().find(QStringLiteral(" with spaces ")));
QVERIFY(fakeFolder.currentLocalState().find(QStringLiteral("with spaces")));
QVERIFY(!fakeFolder.currentLocalState().find(QStringLiteral(" with spaces ")));
QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral(" with spaces "))->_status, SyncFileItem::Status::Success);
}
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile()
void testCreateFileWithTrailingSpaces_remoteDontGetRenamedAutomatically()
{
FakeFolder fakeFolder{FileInfo{}};
// On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
FakeFolder fakeFolder{FileInfo()};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces4("A/ foo");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
fakeFolder.remoteModifier().mkdir("A");
@ -300,43 +274,69 @@ private slots:
fakeFolder.remoteModifier().insert(fileWithSpaces5);
fakeFolder.remoteModifier().insert(fileWithSpaces6);
qDebug() << fakeFolder.currentRemoteState();
ItemCompletedSpy completeSpy(fakeFolder);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
qDebug() << fakeFolder.currentRemoteState();
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
auto expectedState = fakeFolder.currentLocalState();
QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
if (Utility::isWindows()) {
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
} else {
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
}
}
void testCreateFileWithTrailingSpaces_localTrimmedDoesExist_dontRenameAndUploadFile()
void testCreateFileWithTrailingSpaces_remoteGetRenamedManually()
{
// On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
FakeFolder fakeFolder{FileInfo()};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces4("A/ foo");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
const QString fileWithoutSpaces4("A/foo");
const QString fileWithoutSpaces5("A/bar");
const QString fileWithoutSpaces6("A/bla");
fakeFolder.remoteModifier().mkdir("A");
fakeFolder.remoteModifier().insert(fileWithSpaces4);
fakeFolder.remoteModifier().insert(fileWithSpaces5);
fakeFolder.remoteModifier().insert(fileWithSpaces6);
ItemCompletedSpy completeSpy(fakeFolder);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
if (Utility::isWindows()) {
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
} else {
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
}
fakeFolder.remoteModifier().rename(fileWithSpaces4, fileWithoutSpaces4);
fakeFolder.remoteModifier().rename(fileWithSpaces5, fileWithoutSpaces5);
fakeFolder.remoteModifier().rename(fileWithSpaces6, fileWithoutSpaces6);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(completeSpy.findItem(fileWithoutSpaces4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithoutSpaces5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithoutSpaces6)->_status, SyncFileItem::Status::Success);
}
void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAutomaticallyAndDontUploadFile()
{
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@ -344,9 +344,9 @@ private slots:
const QString fileTrimmed("foo");
fakeFolder.localModifier().insert(fileTrimmed);
QVERIFY(fakeFolder.syncOnce());
fakeFolder.localModifier().insert(fileWithSpaces);
QVERIFY(!fakeFolder.syncOnce());
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
@ -354,7 +354,7 @@ private slots:
QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
}
void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAndUploadFile()
void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAutomaticallyAndUploadBothFiles()
{
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@ -363,10 +363,13 @@ private slots:
fakeFolder.localModifier().insert(fileTrimmed);
fakeFolder.localModifier().insert(fileWithSpaces);
QVERIFY(!fakeFolder.syncOnce());
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces);
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces));
QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
}
@ -376,7 +379,7 @@ private slots:
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces1(" foo");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
fakeFolder.localModifier().insert(fileWithSpaces1);

View File

@ -763,17 +763,17 @@ private slots:
QVERIFY(dbRecord(fakeFolder, "case6-rename")._type == ItemTypeFile);
}
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameAndUploadFile()
void testCreateFileWithTrailingSpaces_acceptAndRejectInvalidFileName()
{
FakeFolder fakeFolder{ FileInfo() };
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces1(" foo");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
const QString fileWithSpaces4("A/ foo");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
fakeFolder.localModifier().insert(fileWithSpaces1);
@ -783,101 +783,133 @@ private slots:
fakeFolder.localModifier().insert(fileWithSpaces4);
fakeFolder.localModifier().insert(fileWithSpaces5);
fakeFolder.localModifier().insert(fileWithSpaces6);
ItemCompletedSpy completeSpy(fakeFolder);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces1);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces2);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces3);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces4);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces5);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces6);
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces1.trimmed()));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces1));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces2.trimmed()));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces2));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces3.trimmed()));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces3));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
}
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile()
void testCreateFileWithTrailingSpaces_remoteDontGetRenamedAutomatically()
{
// On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
FakeFolder fakeFolder{ FileInfo() };
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces4("A/ foo");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
const QString fileWithSpacesVirtual4(fileWithSpaces4 + DVSUFFIX);
const QString fileWithSpacesVirtual5(fileWithSpaces5 + DVSUFFIX);
const QString fileWithSpacesVirtual6(fileWithSpaces6 + DVSUFFIX);
fakeFolder.remoteModifier().mkdir("A");
fakeFolder.remoteModifier().insert(fileWithSpaces4);
fakeFolder.remoteModifier().insert(fileWithSpaces5);
fakeFolder.remoteModifier().insert(fileWithSpaces6);
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
ItemCompletedSpy completeSpy(fakeFolder);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
QVERIFY(fakeFolder.currentLocalState().find("A/foo" DVSUFFIX));
QVERIFY(!fakeFolder.currentLocalState().find(QString{fileWithSpaces4 + DVSUFFIX}));
if (Utility::isWindows()) {
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
} else {
QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual6)->_status, SyncFileItem::Status::Success);
}
QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
QVERIFY(fakeFolder.currentLocalState().find("A/bar" DVSUFFIX));
QVERIFY(!fakeFolder.currentLocalState().find(QString{fileWithSpaces5 + DVSUFFIX}));
}
QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
QVERIFY(fakeFolder.currentLocalState().find("A/bla" DVSUFFIX));
QVERIFY(!fakeFolder.currentLocalState().find(QString{fileWithSpaces6 + DVSUFFIX}));
void testCreateFileWithTrailingSpaces_remoteGetRenamedManually()
{
// On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
FakeFolder fakeFolder{FileInfo()};
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces4("A/ foo");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
const QString fileWithSpacesVirtual4(fileWithSpaces4 + DVSUFFIX);
const QString fileWithSpacesVirtual5(fileWithSpaces5 + DVSUFFIX);
const QString fileWithSpacesVirtual6(fileWithSpaces6 + DVSUFFIX);
const QString fileWithoutSpaces4("A/foo");
const QString fileWithoutSpaces5("A/bar");
const QString fileWithoutSpaces6("A/bla");
const QString fileWithoutSpacesVirtual4(fileWithoutSpaces4 + DVSUFFIX);
const QString fileWithoutSpacesVirtual5(fileWithoutSpaces5 + DVSUFFIX);
const QString fileWithoutSpacesVirtual6(fileWithoutSpaces6 + DVSUFFIX);
fakeFolder.remoteModifier().mkdir("A");
fakeFolder.remoteModifier().insert(fileWithSpaces4);
fakeFolder.remoteModifier().insert(fileWithSpaces5);
fakeFolder.remoteModifier().insert(fileWithSpaces6);
ItemCompletedSpy completeSpy(fakeFolder);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
if (Utility::isWindows()) {
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
} else {
QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual6)->_status, SyncFileItem::Status::Success);
}
fakeFolder.remoteModifier().rename(fileWithSpaces4, fileWithoutSpaces4);
fakeFolder.remoteModifier().rename(fileWithSpaces5, fileWithoutSpaces5);
fakeFolder.remoteModifier().rename(fileWithSpaces6, fileWithoutSpaces6);
completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
if (Utility::isWindows()) {
QCOMPARE(completeSpy.findItem(fileWithoutSpaces4 + DVSUFFIX)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithoutSpaces5 + DVSUFFIX)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithoutSpaces6 + DVSUFFIX)->_status, SyncFileItem::Status::Success);
} else {
QCOMPARE(completeSpy.findItem(fileWithoutSpacesVirtual4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithoutSpacesVirtual5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithoutSpacesVirtual6)->_status, SyncFileItem::Status::Success);
}
}
// Dehydration via sync works