File indexing completed on 2024-05-05 04:35:29

0001 /*
0002  * This file is part of KDevelop Krazy2 Plugin.
0003  *
0004  * Copyright 2012 Daniel Calviño Sánchez <danxuliu@gmail.com>
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License
0008  * as published by the Free Software Foundation; either version 2
0009  * of the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program. If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include <QTest>
0021 
0022 #include <QListView>
0023 #include <QFileDialog>
0024 #include <QDialogButtonBox>
0025 #include <QPushButton>
0026 #include <QFileSystemModel>
0027 #include <QLineEdit>
0028 
0029 #include <QTimer>
0030 
0031 #include "../settings/selectpathswidget.h"
0032 
0033 class SelectPathsWidgetTest: public QObject {
0034 Q_OBJECT
0035 private slots:
0036 
0037     void initTestCase();
0038     void init();
0039 
0040     void testConstructor();
0041     void testConstructorWithPathsDuplicatedAndNotSorted();
0042     void testConstructorWithInvalidPaths();
0043 
0044     void testAddFile();
0045     void testAddFiles();
0046     void testAddDuplicatedAndNotSortedFiles();
0047     void testRemoveButtonDisabledWhenFileAdded();
0048 
0049     void testRemove();
0050     void testRemoveSeveralPaths();
0051 
0052     void testSelectAndDeselect();
0053 
0054 private:
0055 
0056     bool examplesInSubdirectory() const;
0057 
0058     QPushButton* addButton(const SelectPathsWidget* widget) const;
0059     QPushButton* removeButton(const SelectPathsWidget* widget) const;
0060     QListView* pathsView(const SelectPathsWidget* widget) const;
0061 
0062     void assertPaths(const SelectPathsWidget* widget, const QStringList& paths) const;
0063 
0064     void queueSelectPaths(const SelectPathsWidget* widget,
0065                           const QString& directory,
0066                           const QStringList& paths);
0067 
0068     QString m_examplesPath;
0069 };
0070 
0071 void SelectPathsWidgetTest::initTestCase()
0072 {
0073     m_examplesPath = QStringLiteral(EXAMPLETESTDATA_PATH);
0074 }
0075 
0076 void SelectPathsWidgetTest::init() {
0077     if (!examplesInSubdirectory()) {
0078         QString message = "The examples were not found in the 'examples' directory (" + m_examplesPath + ')';
0079         QSKIP(message.toLatin1(), SkipAll);
0080     }
0081 }
0082 
0083 void SelectPathsWidgetTest::testConstructor() {
0084     QWidget parent;
0085     QStringList paths;
0086     paths << m_examplesPath + "severalIssuesSeveralCheckers.cpp";
0087     paths << m_examplesPath + "singleIssue.cpp";
0088     paths << m_examplesPath + "subdirectory";
0089     auto  widget = new SelectPathsWidget(paths, &parent);
0090 
0091     QCOMPARE(widget->parent(), &parent);
0092 
0093     assertPaths(widget, QStringList() << m_examplesPath + "severalIssuesSeveralCheckers.cpp"
0094                                       << m_examplesPath + "singleIssue.cpp"
0095                                       << m_examplesPath + "subdirectory/");
0096 
0097     QCOMPARE(pathsView(widget)->editTriggers(), QAbstractItemView::NoEditTriggers);
0098 }
0099 
0100 void SelectPathsWidgetTest::testConstructorWithPathsDuplicatedAndNotSorted() {
0101     QWidget parent;
0102     QStringList paths;
0103     paths << m_examplesPath + "singleIssue.cpp";
0104     paths << m_examplesPath + "subdirectory";
0105     paths << m_examplesPath + "subdirectory/";
0106     paths << m_examplesPath + "severalIssuesSeveralCheckers.cpp";
0107     paths << m_examplesPath + "singleIssue.cpp";
0108     auto  widget = new SelectPathsWidget(paths, &parent);
0109 
0110     QCOMPARE(widget->parent(), &parent);
0111 
0112     assertPaths(widget, QStringList() << m_examplesPath + "severalIssuesSeveralCheckers.cpp"
0113                                       << m_examplesPath + "singleIssue.cpp"
0114                                       << m_examplesPath + "subdirectory/");
0115 }
0116 
0117 void SelectPathsWidgetTest::testConstructorWithInvalidPaths() {
0118     QWidget parent;
0119     QStringList paths;
0120     paths << m_examplesPath + "severalIssuesSeveralCheckers.cpp";
0121     paths << m_examplesPath + "singleIssue.cpp";
0122     paths << "examples/severalIssuesSingleChecker.cpp";
0123     paths << m_examplesPath + "subdirectory";
0124     paths << m_examplesPath + "fileThatDoesNotExist.cpp";
0125     auto  widget = new SelectPathsWidget(paths, &parent);
0126 
0127     QCOMPARE(widget->parent(), &parent);
0128 
0129     assertPaths(widget, QStringList() << m_examplesPath + "severalIssuesSeveralCheckers.cpp"
0130                                       << m_examplesPath + "singleIssue.cpp"
0131                                       << m_examplesPath + "subdirectory/");
0132 }
0133 
0134 void SelectPathsWidgetTest::testAddFile() {
0135     QStringList paths;
0136     SelectPathsWidget widget(paths);
0137 
0138     queueSelectPaths(&widget, m_examplesPath,
0139                      QStringList() << "singleIssue.cpp");
0140     addButton(&widget)->click();
0141 
0142     assertPaths(&widget, QStringList() << m_examplesPath + "singleIssue.cpp");
0143 }
0144 
0145 void SelectPathsWidgetTest::testAddFiles() {
0146     QStringList paths;
0147     SelectPathsWidget widget(paths);
0148 
0149     queueSelectPaths(&widget, m_examplesPath,
0150                      QStringList() << "singleExtraIssue.cpp"
0151                                    << QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp"));
0152     addButton(&widget)->click();
0153 
0154     assertPaths(&widget, QStringList() << m_examplesPath + "singleExtraIssue.cpp"
0155                                        << m_examplesPath + QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp"));
0156 }
0157 
0158 void SelectPathsWidgetTest::testAddDuplicatedAndNotSortedFiles() {
0159     QStringList paths;
0160     paths << m_examplesPath + "singleExtraIssue.cpp";
0161     SelectPathsWidget widget(paths);
0162 
0163     queueSelectPaths(&widget, m_examplesPath,
0164                      QStringList() << "singleExtraIssue.cpp"
0165                                    << QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp")
0166                                    << QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp")
0167                                    << QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp"));
0168     addButton(&widget)->click();
0169 
0170     assertPaths(&widget, QStringList() << m_examplesPath + "singleExtraIssue.cpp"
0171                                        << m_examplesPath + QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp"));
0172 }
0173 
0174 void SelectPathsWidgetTest::testRemoveButtonDisabledWhenFileAdded() {
0175     QStringList paths;
0176     paths << m_examplesPath + "singleIssue.cpp";
0177     SelectPathsWidget widget(paths);
0178 
0179     QVERIFY(!removeButton(&widget)->isEnabled());
0180 
0181     QModelIndex index = pathsView(&widget)->model()->index(0, 0);
0182     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::SelectCurrent);
0183 
0184     QVERIFY(removeButton(&widget)->isEnabled());
0185 
0186     queueSelectPaths(&widget, m_examplesPath,
0187                      QStringList() << "singleExtraIssue.cpp");
0188     addButton(&widget)->click();
0189 
0190     QVERIFY(pathsView(&widget)->selectionModel()->selectedIndexes().isEmpty());
0191     QVERIFY(!removeButton(&widget)->isEnabled());
0192 }
0193 
0194 void SelectPathsWidgetTest::testRemove() {
0195     QStringList paths;
0196     paths << m_examplesPath + "severalIssuesSeveralCheckers.cpp";
0197     paths << m_examplesPath + "singleIssue.cpp";
0198     SelectPathsWidget widget(paths);
0199 
0200     QVERIFY(!removeButton(&widget)->isEnabled());
0201 
0202     QModelIndex index = pathsView(&widget)->model()->index(1, 0);
0203     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::SelectCurrent);
0204 
0205     QVERIFY(removeButton(&widget)->isEnabled());
0206 
0207     removeButton(&widget)->click();
0208 
0209     assertPaths(&widget, QStringList() << m_examplesPath + "severalIssuesSeveralCheckers.cpp");
0210 
0211     QVERIFY(!removeButton(&widget)->isEnabled());
0212 }
0213 
0214 void SelectPathsWidgetTest::testRemoveSeveralPaths() {
0215     QStringList paths;
0216     paths << m_examplesPath + "severalIssuesSeveralCheckers.cpp";
0217     paths << m_examplesPath + "singleExtraIssue.cpp";
0218     paths << m_examplesPath + "singleIssue.cpp";
0219 
0220     SelectPathsWidget widget(paths);
0221 
0222     QVERIFY(!removeButton(&widget)->isEnabled());
0223 
0224     QModelIndex index = pathsView(&widget)->model()->index(0, 0);
0225     QVERIFY(index.isValid());
0226     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::Select);
0227 
0228     QVERIFY(removeButton(&widget)->isEnabled());
0229 
0230     index = pathsView(&widget)->model()->index(2, 0);
0231     QVERIFY(index.isValid());
0232     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::Select);
0233 
0234     QVERIFY(removeButton(&widget)->isEnabled());
0235 
0236     removeButton(&widget)->click();
0237 
0238     assertPaths(&widget, QStringList() << m_examplesPath + "singleExtraIssue.cpp");
0239 
0240     QVERIFY(!removeButton(&widget)->isEnabled());
0241 }
0242 
0243 void SelectPathsWidgetTest::testSelectAndDeselect() {
0244     QStringList paths;
0245     paths << m_examplesPath + "severalIssuesSeveralCheckers.cpp";
0246     paths << m_examplesPath + "singleIssue.cpp";
0247     paths << m_examplesPath + "singleExtraIssue.cpp";
0248     SelectPathsWidget widget(paths);
0249 
0250     QModelIndex index = pathsView(&widget)->model()->index(0, 0);
0251     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::Select);
0252 
0253     QVERIFY(removeButton(&widget)->isEnabled());
0254 
0255     index = pathsView(&widget)->model()->index(2, 0);
0256     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::Select);
0257 
0258     QVERIFY(removeButton(&widget)->isEnabled());
0259 
0260     index = pathsView(&widget)->model()->index(0, 0);
0261     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::Deselect);
0262 
0263     QVERIFY(removeButton(&widget)->isEnabled());
0264 
0265     index = pathsView(&widget)->model()->index(2, 0);
0266     pathsView(&widget)->selectionModel()->select(index, QItemSelectionModel::Deselect);
0267 
0268     QVERIFY(!removeButton(&widget)->isEnabled());
0269 }
0270 
0271 ///////////////////////////////// Helpers //////////////////////////////////////
0272 
0273 bool SelectPathsWidgetTest::examplesInSubdirectory() const {
0274     if (QFile(m_examplesPath + "singleIssue.cpp").exists() &&
0275         QFile(m_examplesPath + "singleExtraIssue.cpp").exists() &&
0276         QFile(m_examplesPath + QString::fromUtf8("singleIssueNonAsciiFileNameḶḷambión.cpp")).exists() &&
0277         QFile(m_examplesPath + ".singleIssueHiddenUnixFileName.cpp").exists() &&
0278         QFile(m_examplesPath + "severalIssuesSingleChecker.cpp").exists() &&
0279         QFile(m_examplesPath + "severalIssuesSeveralCheckers.cpp").exists() &&
0280         QFile(m_examplesPath + "severalIssuesSeveralCheckersUnknownFileType.dqq").exists() &&
0281         QFile(m_examplesPath + "subdirectory/singleIssue.desktop").exists() &&
0282         QFile(m_examplesPath + "subdirectory/severalIssuesSeveralCheckers.qml").exists()) {
0283         return true;
0284     }
0285 
0286     return false;
0287 }
0288 
0289 QPushButton* SelectPathsWidgetTest::addButton(const SelectPathsWidget* widget) const {
0290     return widget->findChild<QPushButton*>("addButton");
0291 }
0292 
0293 QPushButton* SelectPathsWidgetTest::removeButton(const SelectPathsWidget* widget) const {
0294     return widget->findChild<QPushButton*>("removeButton");
0295 }
0296 
0297 QListView* SelectPathsWidgetTest::pathsView(const SelectPathsWidget* widget) const {
0298     return widget->findChild<QListView*>("pathsView");
0299 }
0300 
0301 void SelectPathsWidgetTest::assertPaths(const SelectPathsWidget* widget,
0302                                         const QStringList& paths) const {
0303     QCOMPARE(widget->selectedFilesAndDirectories().count(), paths.count());
0304     for (int i=0; i<paths.count(); ++i) {
0305         QCOMPARE(widget->selectedFilesAndDirectories()[i], paths[i]);
0306     }
0307 
0308     QCOMPARE(pathsView(widget)->model()->rowCount(), paths.count());
0309     for (int i=0; i<paths.count(); ++i) {
0310         QModelIndex index = pathsView(widget)->model()->index(i, 0);
0311         QCOMPARE(pathsView(widget)->model()->data(index).toString(), paths[i]);
0312     }
0313 }
0314 
0315 //The file dialog is modal, so it won't return to the test code until it is
0316 //closed. Thus, the actions to be performed while the file dialog is being shown
0317 //(like accepting the file dialog itself) must be "queued".
0318 //Instead of queueing them to be performed after some fixed amount of time,
0319 //it is checked if the action can be performed and, if not, the action is
0320 //retried again after a little amount of time.
0321 class QueuedSelectPathsAction: public QObject {
0322 Q_OBJECT
0323 public:
0324 
0325     const SelectPathsWidget* m_widget;
0326     QString m_directory;
0327     QStringList m_paths;
0328 
0329     QueuedSelectPathsAction(QObject* parent): QObject(parent) {
0330     }
0331 
0332 public Q_SLOTS:
0333 
0334     void selectPaths() {
0335         QFileDialog* fileDialog = m_widget->findChild<QFileDialog*>();
0336         if (!fileDialog || !fileDialog->isVisible()) {
0337             QTimer::singleShot(100, this, SLOT(selectPaths()));
0338             return;
0339         }
0340 
0341         fileDialog->setDirectory(m_directory);
0342 
0343         QListView *lv = fileDialog->findChild<QListView*>("listView");
0344         QVERIFY(lv != nullptr);
0345 
0346         QFileSystemModel *model = dynamic_cast<QFileSystemModel*>(lv->model());
0347         QVERIFY(model != nullptr);
0348 
0349         QLineEdit *lineEdit = fileDialog->findChild<QLineEdit*>("fileNameEdit");
0350         QVERIFY(lineEdit != nullptr);
0351 
0352         foreach (const QString& path, m_paths) {
0353             QModelIndex idx = model->index(m_directory + QStringLiteral("/") + path);
0354             if (!idx.isValid())
0355                 continue;
0356             lv->selectionModel()->select(idx, QItemSelectionModel::Select);
0357         }
0358 
0359         QString line;
0360         foreach (const QString& path, m_paths) {
0361             line += '"';
0362             line += path;
0363             line += '"';
0364             line += ' ';
0365         }
0366         line.resize(line.size() - 1);
0367         lineEdit->setText(line);
0368 
0369         QDialogButtonBox *box = fileDialog->findChild<QDialogButtonBox*>();
0370         QVERIFY(box != nullptr);
0371         QPushButton *button = box->button(QDialogButtonBox::Open);
0372         QVERIFY(button != nullptr);
0373         QVERIFY(button->isEnabled());
0374         button->click();
0375     }
0376 
0377 };
0378 
0379 void SelectPathsWidgetTest::queueSelectPaths(const SelectPathsWidget* widget,
0380                                              const QString& directory,
0381                                              const QStringList& paths) {
0382     auto  helper = new QueuedSelectPathsAction(this);
0383     helper->m_widget = widget;
0384     helper->m_directory = directory;
0385     helper->m_paths = paths;
0386     helper->selectPaths();
0387 }
0388 
0389 QTEST_MAIN(SelectPathsWidgetTest)
0390 
0391 #include "selectpathswidgettest.moc"