File: knewfilemenutest.cpp

package info (click to toggle)
kio 5.116.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 41,496 kB
  • sloc: cpp: 123,468; xml: 528; ansic: 466; ruby: 60; sh: 21; makefile: 13
file content (330 lines) | stat: -rw-r--r-- 13,949 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/*
    This file is part of the KDE libraries
    SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org>

    SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/

#include <QTest>

#include <KActionCollection>
#include <KIO/StoredTransferJob>
#include <KShell>
#include <QDialog>
#include <QLineEdit>
#include <QMenu>
#include <knameandurlinputdialog.h>
#include <knewfilemenu.h>
#include <kpropertiesdialog.h>

#include <QPushButton>
#include <QSignalSpy>
#include <QStandardPaths>
#include <QTemporaryDir>

#ifdef Q_OS_UNIX
#include <sys/stat.h>
#include <sys/types.h>
#endif

#include <algorithm>

class KNewFileMenuTest : public QObject
{
    Q_OBJECT
private Q_SLOTS:
    void initTestCase()
    {
        QStandardPaths::setTestModeEnabled(true);
#ifdef Q_OS_UNIX
        m_umask = ::umask(0);
        ::umask(m_umask);
#endif
        QVERIFY(m_tmpDir.isValid());

        // These have to be created here before KNewFileMenuSingleton is created,
        // otherwise they wouldn't be picked up
        QDir dir;
        m_xdgConfigDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
        QVERIFY(dir.mkpath(m_xdgConfigDir));
        QFile userDirs(m_xdgConfigDir + "/user-dirs.dirs");
        QVERIFY(userDirs.open(QIODevice::WriteOnly));
        const QString templDir = "XDG_TEMPLATES_DIR=\"" + m_xdgConfigDir + "/test-templates/\"\n";
        userDirs.write(templDir.toLocal8Bit());
        userDirs.close();

        // Different location than what KNewFileMenuPrivate::slotFillTemplates() checks by default
        const QString loc = m_xdgConfigDir + '/' + "test-templates/";
        QVERIFY(dir.mkpath(loc));

        QFile templ(m_xdgConfigDir + "/test-templates" + "/test-text.desktop");
        QVERIFY(templ.open(QIODevice::WriteOnly));
        const QByteArray contents =
            "[Desktop Entry]\n"
            "Name=Custom...\n"
            "Type=Link\n"
            "URL=TestTextFile.txt\n"
            "Icon=text-plain\n";

        templ.write(contents);
        templ.close();
    }

    void cleanupTestCase()
    {
        QFile::remove(m_xdgConfigDir + "/user-dirs.dirs");
        QDir(m_xdgConfigDir + "/test-templates").removeRecursively();
    }

    // Ensure that we can use storedPut() with a qrc file as input
    // similar to JobTest::storedPutIODeviceFile, but with a qrc file as input
    // (and here because jobtest doesn't link to KIO::FileWidgets, which has the qrc)
    void storedPutIODeviceQrcFile()
    {
        // Given a source (in a Qt resource file) and a destination file
        const QString src = QStringLiteral(":/kio5/newfile-templates/.source/HTMLFile.html");
        QVERIFY(QFile::exists(src));
        QFile srcFile(src);
        QVERIFY(srcFile.open(QIODevice::ReadOnly));
        const QString dest = m_tmpDir.path() + QStringLiteral("/dest");
        QFile::remove(dest);
        const QUrl destUrl = QUrl::fromLocalFile(dest);

        // When using storedPut with the QFile as argument
        KIO::StoredTransferJob *job = KIO::storedPut(&srcFile, destUrl, -1, KIO::Overwrite | KIO::HideProgressInfo);

        // Then the copy should succeed and the dest file exist
        QVERIFY2(job->exec(), qPrintable(job->errorString()));
        QVERIFY(QFile::exists(dest));
        QCOMPARE(QFileInfo(src).size(), QFileInfo(dest).size());
        // And the permissions should respect the umask (#359581)
#ifdef Q_OS_UNIX
        if (m_umask & S_IWOTH) {
            QVERIFY2(!(QFileInfo(dest).permissions() & QFileDevice::WriteOther), qPrintable(dest));
        }
        if (m_umask & S_IWGRP) {
            QVERIFY(!(QFileInfo(dest).permissions() & QFileDevice::WriteGroup));
        }
#endif
        QFile::remove(dest);
    }

    void test_data()
    {
        QTest::addColumn<QString>("actionText"); // the action we're clicking on
        QTest::addColumn<QString>("expectedDefaultFilename"); // the initial filename in the dialog
        QTest::addColumn<QString>("typedFilename"); // what the user is typing
        QTest::addColumn<QString>("expectedFilename"); // the final file name

        QTest::newRow("text file") << "Text File"
                                   << "Text File.txt"
                                   << "tmp_knewfilemenutest.txt"
                                   << "tmp_knewfilemenutest.txt";
        QTest::newRow("text file with jpeg extension") << "Text File"
                                                       << "Text File.txt"
                                                       << "foo.jpg"
                                                       << "foo.jpg"; // You get what you typed
        QTest::newRow("html file") << "HTML File"
                                   << "HTML File.html"
                                   << "foo.html"
                                   << "foo.html";
        QTest::newRow("url desktop file") << "Link to Location "
                                          << ""
                                          << "tmp_link.desktop"
                                          << "tmp_link.desktop";
        QTest::newRow("url desktop file no extension") << "Link to Location "
                                                       << ""
                                                       << "tmp_link1"
                                                       << "tmp_link1.desktop";
        QTest::newRow("url desktop file .pl extension") << "Link to Location "
                                                        << ""
                                                        << "tmp_link.pl"
                                                        << "tmp_link.pl.desktop";
        QTest::newRow("symlink") << "Link to File"
                                 << ""
                                 << "thelink"
                                 << "thelink";
        QTest::newRow("folder") << "Folder..."
                                << "New Folder"
                                << "folder1"
                                << "folder1";
        QTest::newRow("folder_named_tilde") << "Folder..."
                                            << "New Folder"
                                            << "~"
                                            << "~";

        // ~/.qttest/share/folderTildeExpanded
        const QString tildeDirPath =
            KShell::tildeCollapse(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/folderTildeExpanded"));
        QVERIFY(tildeDirPath.startsWith(QLatin1Char('~')));
        QTest::newRow("folder_tilde_expanded") << "Folder..."
                                               << "New Folder" << tildeDirPath << "folderTildeExpanded";

        QTest::newRow("folder_default_name") << "Folder..."
                                             << "New Folder"
                                             << "New Folder"
                                             << "New Folder";
        QTest::newRow("folder_with_suggested_name") << "Folder..."
                                                    << "New Folder (1)"
                                                    << "New Folder (1)"
                                                    << "New Folder (1)";
        QTest::newRow("folder_with_suggested_name_but_user_overrides") << "Folder..."
                                                                       << "New Folder (2)"
                                                                       << "New Folder"
                                                                       << "";
        QTest::newRow("application") << "Link to Application..."
                                     << "Link to Application"
                                     << "app1"
                                     << "app1.desktop";
    }

    void test()
    {
        QFETCH(QString, actionText);
        QFETCH(QString, expectedDefaultFilename);
        QFETCH(QString, typedFilename);
        QFETCH(QString, expectedFilename);

        QWidget parentWidget;
#if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
        KActionCollection coll(this, QStringLiteral("foo"));
        KNewFileMenu menu(&coll, QStringLiteral("the_action"), this);
#else
        KNewFileMenu menu(this);
#endif
        menu.setModal(false);
        menu.setParentWidget(&parentWidget);
        menu.setSelectDirWhenAlreadyExist(true);
        menu.setWorkingDirectory(QUrl::fromLocalFile(m_tmpDir.path()));
        menu.checkUpToDate();
#if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
        QAction *action = coll.action(QStringLiteral("the_action"));
#else
        QAction *action = &menu;
#endif
        QVERIFY(action);
        QAction *textAct = nullptr;
        const QList<QAction *> actionsList = action->menu()->actions();
        for (QAction *act : actionsList) {
            if (act->text().contains(actionText)) {
                textAct = act;
            }
        }
        if (!textAct) {
            for (const QAction *act : actionsList) {
                qDebug() << act << act->text() << act->data();
            }
            const QString err = QLatin1String("action with text \"") + actionText + QLatin1String("\" not found.");
            QVERIFY2(textAct, qPrintable(err));
        }
        textAct->trigger();

        QDialog *dialog;
        // QTRY_ because a NameFinderJob could be running and the dialog will be shown when
        // it finishes.
        QTRY_VERIFY(dialog = parentWidget.findChild<QDialog *>());

        const auto buttonsList = dialog->findChildren<QPushButton *>();
        auto it = std::find_if(buttonsList.cbegin(), buttonsList.cend(), [](const QPushButton *button) {
            return button->text().contains("OK");
        });
        QVERIFY(it != buttonsList.cend());
        QPushButton *okButton = *it;

        if (KNameAndUrlInputDialog *nauiDialog = qobject_cast<KNameAndUrlInputDialog *>(dialog)) {
            QCOMPARE(nauiDialog->name(), expectedDefaultFilename);
            nauiDialog->setSuggestedName(typedFilename);
            nauiDialog->setSuggestedUrl(QUrl(QStringLiteral("file:///etc")));
        } else if (KPropertiesDialog *propsDialog = qobject_cast<KPropertiesDialog *>(dialog)) {
            QLineEdit *lineEdit = propsDialog->findChild<QLineEdit *>(QStringLiteral("fileNameLineEdit"));
            QVERIFY(lineEdit);
            QCOMPARE(lineEdit->text(), expectedDefaultFilename);
            lineEdit->setText(typedFilename);
        } else {
            QLineEdit *lineEdit = dialog->findChild<QLineEdit *>();
            QVERIFY(lineEdit);
            QCOMPARE(lineEdit->text(), expectedDefaultFilename);
            lineEdit->setText(typedFilename);
        }
        QUrl emittedUrl;
        QSignalSpy spy(&menu, &KNewFileMenu::fileCreated);
        QSignalSpy folderSpy(&menu, &KNewFileMenu::directoryCreated);

        // expectedFilename is empty in the "Folder already exists" case, the button won't
        // become enabled.
        if (!expectedFilename.isEmpty()) {
            // For all other cases, QTRY_ because we may be waiting for the StatJob in
            // KNewFileMenuPrivate::_k_delayedSlotTextChanged() to finish, the OK button
            // is disabled while it's checking if a folder/file with that name already exists.
            QTRY_VERIFY(okButton->isEnabled());
        }

        okButton->click();
        QString path = m_tmpDir.path() + QLatin1Char('/') + expectedFilename;
        if (typedFilename.contains(QLatin1String("folderTildeExpanded"))) {
            path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + QLatin1String("folderTildeExpanded");
        }
        if (actionText == QLatin1String("Folder...")) {
            if (expectedFilename.isEmpty()) {
                // This is the "Folder already exists" case; expect an error dialog
                okButton->click();
                path.clear();
            } else {
                QVERIFY(folderSpy.wait(1000));
                emittedUrl = folderSpy.at(0).at(0).toUrl();
                QVERIFY(QFileInfo(path).isDir());
            }
        } else {
            if (spy.isEmpty()) {
                QVERIFY(spy.wait(1000));
            }
            emittedUrl = spy.at(0).at(0).toUrl();
            QVERIFY(QFile::exists(path));
            if (actionText != QLatin1String("Link to File")) {
                QFile file(path);
                QVERIFY(file.open(QIODevice::ReadOnly));
                const QByteArray contents = file.readAll();
                if (actionText.startsWith(QLatin1String("HTML"))) {
                    QCOMPARE(QString::fromLatin1(contents.left(6)), QStringLiteral("<!DOCT"));
                }
            }
        }
        QCOMPARE(emittedUrl.toLocalFile(), path);
    }

    void testParsingUserDirs()
    {
#if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
        KActionCollection coll(this, QStringLiteral("foo"));
        KNewFileMenu menu(&coll, QStringLiteral("the_action"), this);
#else
        KNewFileMenu menu(this);
#endif
        menu.setWorkingDirectory(QUrl::fromLocalFile(m_tmpDir.path()));
        menu.checkUpToDate();
#if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
        QAction *action = coll.action(QStringLiteral("the_action"));
#else
        QAction *action = &menu;
#endif
        const auto list = action->menu()->actions();
        auto it = std::find_if(list.cbegin(), list.cend(), [](QAction *act) {
            return act->text().contains("Custom");
        });
        QVERIFY(it != list.cend());
        // There is a separator between system-wide templates and the ones
        // from the user's home
        QVERIFY((*--it)->isSeparator());
    }

private:
    QTemporaryDir m_tmpDir;
    QString m_xdgConfigDir;
#ifdef Q_OS_UNIX
    mode_t m_umask;
#endif
};

QTEST_MAIN(KNewFileMenuTest)

#include "knewfilemenutest.moc"