~osomon/oxide/ensure-files-exist

« back to all changes in this revision

Viewing changes to qt/tests/qmltests/main.cc

  • Committer: Olivier Tilloy
  • Date: 2014-09-25 16:27:09 UTC
  • mfrom: (677.1.95 oxide)
  • Revision ID: olivier.tilloy@canonical.com-20140925162709-h8bai0f1nfaf7cfy
Merge the latest changes from trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
// License along with this library; if not, write to the Free Software
16
16
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17
17
 
 
18
#include <QDir>
 
19
#include <QDirIterator>
18
20
#include <QGuiApplication>
19
21
#include <QLatin1String>
 
22
#include <QList>
 
23
#include <QQmlContext>
 
24
#include <QQmlEngine>
 
25
#include <QQmlError>
 
26
#include <QQuickView>
20
27
#include <QString>
 
28
#include <QStringList>
 
29
#include <QtDebug>
 
30
#include <QTest>
 
31
#include <QTextStream>
21
32
#include <QtGlobal>
22
 
#include <QtQuickTest/quicktest.h>
 
33
#include <QtQuickTest/private/qtestoptions_p.h>
 
34
#include <QtQuickTest/private/quicktestresult_p.h>
23
35
#include <QtQuickVersion>
 
36
#include <QUrl>
24
37
#if defined(ENABLE_COMPOSITING)
25
38
#include <QOpenGLContext>
26
39
#if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
30
43
#endif
31
44
#endif
32
45
 
 
46
#include "qt/core/api/oxideqglobal.h"
 
47
 
 
48
// We don't use quick_test_main() here for running the qmltest binary as we want to
 
49
// be able to have a per-test datadir. However, some of quick_test_main() is
 
50
// duplicated here because we still use other bits of the QtQuickTest module
 
51
 
 
52
class QTestRootObject : public QObject
 
53
{
 
54
  Q_OBJECT
 
55
  Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged)
 
56
  Q_PROPERTY(bool hasTestCase READ hasTestCase WRITE setHasTestCase NOTIFY hasTestCaseChanged)
 
57
 
 
58
 public:
 
59
  QTestRootObject(QObject* parent = 0)
 
60
      : QObject(parent),
 
61
        has_quit_(false), window_shown_(false), has_test_case_(false) {}
 
62
 
 
63
  static QTestRootObject* instance() {
 
64
    static QPointer<QTestRootObject> object = new QTestRootObject();
 
65
    Q_ASSERT(object);
 
66
    return object;
 
67
  }
 
68
 
 
69
  bool has_quit_:1;
 
70
  bool hasTestCase() const { return has_test_case_; }
 
71
  void setHasTestCase(bool value) { has_test_case_ = value; emit hasTestCaseChanged(); }
 
72
 
 
73
  bool windowShown() const { return window_shown_; }
 
74
  void setWindowShown(bool value) { window_shown_ = value; emit windowShownChanged(); }
 
75
 
 
76
  void init() { setWindowShown(false); setHasTestCase(false); has_quit_ = false; }
 
77
 
 
78
 Q_SIGNALS:
 
79
  void windowShownChanged();
 
80
  void hasTestCaseChanged();
 
81
 
 
82
 private Q_SLOTS:
 
83
  void quit() { has_quit_ = true; }
 
84
 
 
85
 private:
 
86
  bool window_shown_:1;
 
87
  bool has_test_case_:1;
 
88
};
 
89
 
 
90
static QObject* GetTestRootObject(QQmlEngine* engine, QJSEngine* js_engine)
 
91
{
 
92
  Q_UNUSED(engine);
 
93
  Q_UNUSED(js_engine);
 
94
  return QTestRootObject::instance();
 
95
}
 
96
 
 
97
static void HandleCompileErrors(const QFileInfo& fi, QQuickView* view) {
 
98
  const QList<QQmlError> errors = view->errors();
 
99
 
 
100
  QuickTestResult results;
 
101
  results.setTestCaseName(fi.baseName());
 
102
  results.startLogging();
 
103
  results.setFunctionName(QLatin1String("compile"));
 
104
 
 
105
  QString message;
 
106
  QTextStream str(&message);
 
107
  str << "\n  " << QDir::toNativeSeparators(fi.absoluteFilePath()) << " produced "
 
108
      << errors.size() << " error(s):\n";
 
109
  for (QList<QQmlError>::const_iterator it = errors.begin();
 
110
       it != errors.end(); ++it) {
 
111
    const QQmlError& e = *it;
 
112
    str << "    ";
 
113
    if (e.url().isLocalFile()) {
 
114
      str << QDir::toNativeSeparators(e.url().toLocalFile());
 
115
    } else {
 
116
      str << e.url().toString();
 
117
    }
 
118
    if (e.line() > 0) {
 
119
      str << ':' << e.line() << ',' << e.column();
 
120
    }
 
121
    str << ": " << e.description() << '\n';
 
122
  }
 
123
 
 
124
  str << "  Working directory: "
 
125
      << QDir::toNativeSeparators(QDir::current().absolutePath()) << '\n';
 
126
  if (QQmlEngine *engine = view->engine()) {
 
127
    const QStringList import_paths = engine->importPathList();
 
128
    str << "  View: " << view->metaObject()->className() << ", import paths:\n";
 
129
    for (QStringList::const_iterator it = import_paths.begin();
 
130
         it != import_paths.end(); ++it) {
 
131
      str << "    '" << QDir::toNativeSeparators(*it) << "'\n";
 
132
    }
 
133
    const QStringList plugin_paths = engine->pluginPathList();
 
134
    str << "  Plugin paths:\n";
 
135
    for (QStringList::const_iterator it = plugin_paths.begin();
 
136
         it != plugin_paths.end(); ++it) {
 
137
      str << "    '" << QDir::toNativeSeparators(*it) << "'\n";
 
138
    }
 
139
  }
 
140
 
 
141
  qWarning("%s", qPrintable(message));
 
142
 
 
143
  results.fail(errors.at(0).description(),
 
144
               errors.at(0).url(), errors.at(0).line());
 
145
  results.finishTestData();
 
146
  results.finishTestDataCleanup();
 
147
  results.finishTestFunction();
 
148
  results.setFunctionName(QString());
 
149
  results.stopLogging();
 
150
}
 
151
 
33
152
static QString stripQuotes(const QString& in) {
34
153
  if (in.length() >= 2 && in.startsWith("\"") && in.endsWith("\"")) {
35
154
    return in.mid(1, in.length() - 2);
39
158
}
40
159
 
41
160
int main(int argc, char** argv) {
42
 
  char** filtered_argv = new char*[argc + 1];
43
 
  int filtered_argc = 1;
44
 
  filtered_argv[0] = argv[0];
45
 
 
46
 
  QString name;
 
161
  QStringList imports;
 
162
  QStringList library_paths;
 
163
  QString test_path;
 
164
  QByteArray name;
 
165
  bool use_data_dir = false;
47
166
 
48
167
  int index = 1;
 
168
  int outargc = 1;
49
169
  while (index < argc) {
50
170
    char* arg = argv[index];
51
 
    if (QLatin1String(arg) == QLatin1String("-name") && (index + 1) < argc) {
52
 
      name = stripQuotes(QString::fromLatin1(argv[index + 1]));
53
 
      index += 2;
 
171
    if (QLatin1String(arg) == QLatin1String("-import") && (index + 1) < argc) {
 
172
      imports.append(stripQuotes(QString::fromLatin1(argv[index + 1])));
 
173
      index += 2;
 
174
    } else if (QLatin1String(arg) == QLatin1String("-input") && (index + 1) < argc) {
 
175
      if (!test_path.isEmpty()) {
 
176
        qFatal("Can only specify -input once");
 
177
      }
 
178
      test_path = stripQuotes(QString::fromLatin1(argv[index + 1]));
 
179
      index += 2;
 
180
    } else if (QLatin1String(arg) == QLatin1String("-name") && (index + 1) < argc) {
 
181
      if (!name.isEmpty()) {
 
182
        qFatal("Can only specify -name once");
 
183
      }
 
184
      name = stripQuotes(QString::fromLatin1(argv[index + 1])).toLatin1();
 
185
      index += 2;
 
186
    } else if (QLatin1String(arg) == QLatin1String("-add-library-path") && (index + 1) < argc) {
 
187
      library_paths.append(stripQuotes(QString::fromLatin1(argv[index + 1])));
 
188
      index += 2;
 
189
    } else if (QLatin1String(arg) == QLatin1String("-use-datadir-for-context")) {
 
190
      use_data_dir = true;
 
191
      index += 1;
 
192
    } else if (QLatin1String(arg) == QLatin1String("-nss-db-path") && (index + 1) < argc) {
 
193
      if (!oxideGetNSSDbPath().isEmpty()) {
 
194
        qFatal("Can only specify -nss-db-path once");
 
195
      }
 
196
      if (!oxideSetNSSDbPath(stripQuotes(QString::fromLatin1(argv[index + 1])))) {
 
197
        qFatal("Failed to set NSS DB path");
 
198
      }
 
199
      index += 2;
 
200
    } else if (index != outargc) {
 
201
      argv[outargc++] = argv[index++];
54
202
    } else {
55
 
      filtered_argv[filtered_argc] = arg;
56
 
      ++filtered_argc;
57
 
      ++index;
 
203
      outargc++;
 
204
      index++;
58
205
    }
59
206
  }
60
207
 
61
 
  filtered_argv[filtered_argc] = NULL;
 
208
  argv[outargc] = NULL;
62
209
 
63
 
  QGuiApplication app(filtered_argc, filtered_argv);
 
210
  QGuiApplication app(outargc, argv);
64
211
 
65
212
#if defined(ENABLE_COMPOSITING)
66
213
  QOpenGLContext context;
72
219
#endif
73
220
#endif
74
221
 
75
 
  return quick_test_main(filtered_argc, filtered_argv,
76
 
                         name.toUtf8().constData(), NULL);
 
222
  for (int i = 0; i < library_paths.size(); ++i) {
 
223
    app.addLibraryPath(library_paths[i]);
 
224
  }
 
225
 
 
226
  QuickTestResult::setCurrentAppname(argv[0]);
 
227
  QuickTestResult::setProgramName(name.constData());
 
228
  QuickTestResult::parseArgs(outargc, argv);
 
229
 
 
230
  if (test_path.isEmpty()) {
 
231
    test_path = QDir::currentPath();
 
232
  }
 
233
 
 
234
  QString data_dir(qgetenv("OXIDE_RUNTESTS_TMPDIR"));
 
235
  if (data_dir.isEmpty()) {
 
236
    data_dir = QDir::currentPath();
 
237
  }
 
238
 
 
239
  QStringList files;
 
240
 
 
241
  QFileInfo test_path_info(test_path);
 
242
  if (test_path_info.isFile()) {
 
243
    if (!test_path.endsWith(".qml")) {
 
244
      qFatal("Test file '%s' does not end with '.qml'", qPrintable(test_path));
 
245
    }
 
246
    files.append(test_path);
 
247
  } else if (test_path_info.isDir()) {
 
248
    Q_ASSERT(test_path_info.isDir());
 
249
    const QStringList filters(QStringLiteral("tst_*.qml"));
 
250
    QDirIterator iter(test_path, filters, QDir::Files,
 
251
                      QDirIterator::Subdirectories |
 
252
                      QDirIterator::FollowSymlinks);
 
253
    while (iter.hasNext()) {
 
254
      files.append(iter.next());
 
255
    }
 
256
    files.sort();
 
257
    if (files.isEmpty()) {
 
258
      qFatal("Directory '%s' does not contain any test files",
 
259
             qPrintable(test_path));
 
260
    }
 
261
  } else {
 
262
    qFatal("Test file '%s' does not exist", qPrintable(test_path));
 
263
  }
 
264
 
 
265
  qmlRegisterSingletonType<QTestRootObject>(
 
266
      "Qt.test.qtestroot", 1, 0, "QTestRootObject", GetTestRootObject);
 
267
 
 
268
  QEventLoop event_loop;
 
269
  QQuickView view;
 
270
  view.setFlags(Qt::Window | Qt::WindowSystemMenuHint |
 
271
                Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint |
 
272
                Qt::WindowCloseButtonHint);
 
273
 
 
274
  QObject::connect(view.engine(), SIGNAL(quit()),
 
275
                   QTestRootObject::instance(), SLOT(quit()));
 
276
  QObject::connect(view.engine(), SIGNAL(quit()),
 
277
                   &event_loop, SLOT(quit()));
 
278
 
 
279
  for (QStringList::iterator it = imports.begin(); it != imports.end(); ++it) {
 
280
    view.engine()->addImportPath(*it);
 
281
  }
 
282
  view.rootContext()->setContextProperty(
 
283
      QStringLiteral("QMLTEST_USE_CONTEXT_DATADIR"),
 
284
      use_data_dir);
 
285
 
 
286
  for (QStringList::iterator it = files.begin(); it != files.end(); ++it) {
 
287
    const QFileInfo fi(*it);
 
288
    if (!fi.exists()) {
 
289
      continue;
 
290
    }
 
291
 
 
292
    QDir dir(data_dir);
 
293
    if (files.size() > 1) {
 
294
      dir = data_dir + QDir::separator() + fi.baseName();
 
295
    }
 
296
    view.rootContext()->setContextProperty(
 
297
        QStringLiteral("QMLTEST_DATADIR"),
 
298
        QUrl::fromLocalFile(dir.absolutePath()));
 
299
 
 
300
    view.setObjectName(fi.baseName());
 
301
    view.setTitle(view.objectName());
 
302
 
 
303
    QTestRootObject::instance()->init();
 
304
 
 
305
    QString path = fi.absoluteFilePath();
 
306
    view.setSource(QUrl::fromLocalFile(path));
 
307
 
 
308
    if (QTest::printAvailableFunctions) {
 
309
      continue;
 
310
    }
 
311
 
 
312
    if (view.status() == QQuickView::Error) {
 
313
      HandleCompileErrors(fi, &view);
 
314
      continue;
 
315
    }
 
316
 
 
317
    if (!QTestRootObject::instance()->has_quit_) {
 
318
      view.setFramePosition(QPoint(50, 50));
 
319
      if (view.size().isEmpty()) {
 
320
        qWarning().nospace() << "Test '" << QDir::toNativeSeparators(path) <<
 
321
                                "' has invalid size " << view.size() <<
 
322
                                ", resizing.";
 
323
        view.resize(200, 200);
 
324
      }
 
325
      view.show();
 
326
      view.requestActivate();
 
327
      QTest::qWaitForWindowExposed(&view);
 
328
      if (view.isExposed()) {
 
329
        QTestRootObject::instance()->setWindowShown(true);
 
330
      }
 
331
      if (!QTestRootObject::instance()->has_quit_ &&
 
332
          QTestRootObject::instance()->hasTestCase()) {
 
333
        event_loop.exec();
 
334
      }
 
335
    }
 
336
  }
 
337
 
 
338
  QuickTestResult::setProgramName(NULL);
 
339
  return QuickTestResult::exitCode();
77
340
}
 
341
 
 
342
#include "main.moc"