tst_testcore.cpp 302 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
6
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
8
9
10
11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
28
29
30
**
**************************************************************************/

31
#include "tst_testcore.h"
32
33
34

#include <QScopedPointer>
#include <QLatin1String>
35
#include <QGraphicsObject>
36
37
38
39
40
41
42
43

#include <metainfo.h>
#include <model.h>
#include <modelmerger.h>
#include <modelnode.h>
#include <qmlanchors.h>
#include <invalididexception.h>
#include <invalidmodelnodeexception.h>
44
#include <rewritingexception.h>
45
46
#include <nodeinstanceview.h>
#include <nodeinstance.h>
47
#include <subcomponentmanager.h>
48
49
50
51
52
53
54
55
56
57
58
#include <QDebug>

#include "../testview.h"
#include <variantproperty.h>
#include <abstractproperty.h>
#include <bindingproperty.h>
#include <nodeproperty.h>

#include <nodelistproperty.h>
#include <nodeabstractproperty.h>
#include <componenttextmodifier.h>
59
#include <instances/objectnodeinstance.h>
60
61
62

#include <bytearraymodifier.h>
#include "testrewriterview.h"
63
#include <utils/fileutils.h>
64

65
66
#include <qmljs/qmljsinterpreter.h>

67
#include <QPlainTextEdit>
68
69
#include <private/qdeclarativestate_p.h>
#include <private/qdeclarativemetatype_p.h>
70
#include <QDeclarativeItem>
71

72
//TESTED_COMPONENT=src/plugins/qmldesigner/designercore
73
74
75
76
77

using namespace QmlDesigner;
#include <cstdio>
#include "../common/statichelpers.cpp"

Marco Bubke's avatar
Marco Bubke committed
78
#include <qmljstools/qmljsmodelmanager.h>
79
#include <qmljs/qmljsinterpreter.h>
Marco Bubke's avatar
Marco Bubke committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

#ifdef Q_OS_MAC
#  define SHARE_PATH "/Resources"
#else
#  define SHARE_PATH "/share/qtcreator"
#endif

QString resourcePath()
{
    return QDir::cleanPath(QTCREATORDIR + QLatin1String(SHARE_PATH));
}

class TestModelManager : public QmlJSTools::Internal::ModelManager
{
public:
    TestModelManager() : QmlJSTools::Internal::ModelManager()
    {
        loadQmlTypeDescriptions(resourcePath());
    }
99
    void updateSourceFiles(const QStringList &files, bool emitDocumentOnDiskChanged)
Marco Bubke's avatar
Marco Bubke committed
100
    {
101
        refreshSourceFiles(files, emitDocumentOnDiskChanged).waitForFinished();
Marco Bubke's avatar
Marco Bubke committed
102
    }
103
104
105
106
107
108
109

    QmlJS::LibraryInfo builtins(const QmlJS::Document::Ptr &) const
    {
        return QmlJS::LibraryInfo();
    }


Marco Bubke's avatar
Marco Bubke committed
110
111
};

112
113
114
static void initializeMetaTypeSystem(const QString &resourcePath)
{
    const QDir typeFileDir(resourcePath + QLatin1String("/qml-type-descriptions"));
115
116
    const QStringList qmlExtensions = QStringList() << QLatin1String("*.qml");
    const QFileInfoList qmlFiles = typeFileDir.entryInfoList(qmlExtensions,
117
118
119
                                                             QDir::Files,
                                                             QDir::Name);

120
121
122
123
    QStringList errorsAndWarnings;
    QmlJS::CppQmlTypesLoader::loadQmlTypes(qmlFiles, &errorsAndWarnings, &errorsAndWarnings);
    foreach (const QString &errorAndWarning, errorsAndWarnings)
        qWarning() << qPrintable(errorAndWarning);
124
125
}

126
127
static QmlDesigner::Model* createModel(const QString &typeName, int major = 1, int minor = 1, Model *metaInfoPropxyModel = 0)
{
128
129
    QApplication::processEvents();

130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    QmlDesigner::Model *model = QmlDesigner::Model::create(typeName, major, minor, metaInfoPropxyModel);

    QPlainTextEdit *textEdit = new QPlainTextEdit;
    QObject::connect(model, SIGNAL(destroyed()), textEdit, SLOT(deleteLater()));
    textEdit->setPlainText(QString("import %1 %3.%4; %2{}").arg(typeName.split(".").first())
            .arg(typeName.split(".").last())
            .arg(major)
            .arg(minor));

    NotIndentingTextEditModifier *modifier = new NotIndentingTextEditModifier(textEdit);
    modifier->setParent(textEdit);

    QmlDesigner::RewriterView *rewriterView = new QmlDesigner::RewriterView(QmlDesigner::RewriterView::Validate, model);
    rewriterView->setCheckSemanticErrors(false);
    rewriterView->setTextModifier(modifier);

    model->attachView(rewriterView);

    return model;

}

152
tst_TestCore::tst_TestCore()
153
154
155
156
    : QObject()
{
}

157
void tst_TestCore::initTestCase()
158
159
160
161
162
{
#ifndef QDEBUG_IN_TESTS
    qInstallMsgHandler(testMessageOutput);
#endif
    Exception::setShouldAssert(false);
163

164
165
166
167
168
169
    initializeMetaTypeSystem(QLatin1String(QTCREATORDIR "/share/qtcreator"));


   // Load plugins

#ifdef Q_OS_MAC
170
    const QString pluginPath = QTCREATORDIR "/bin/Qt Creator.app/Contents/PlugIns/QtCreator/QmlDesigner";
171
#else
172
    const QString pluginPath = QTCREATORDIR "/lib/qtcreator/qmldesigner";
173
174
175
176
177
#endif

    qDebug() << pluginPath;
    Q_ASSERT(QFileInfo(pluginPath).exists());
    MetaInfo::setPluginPaths(QStringList() << pluginPath);
Marco Bubke's avatar
Marco Bubke committed
178
179

    new TestModelManager;
180
181
}

182
void tst_TestCore::cleanupTestCase()
183
184
185
186
{
    MetaInfo::clearGlobal();
}

187
188
189
190
191
192
193
194
195
void tst_TestCore::init()
{
    QApplication::processEvents();
}
void tst_TestCore::cleanup()
{
    QApplication::processEvents();
}

196
void tst_TestCore::testModelCreateCoreModel()
197
{
198
    QScopedPointer<Model> model(createModel("QtQuick.Item"));
199
200
    QVERIFY(model.data());

201
    QScopedPointer<TestView> testView(new TestView(model.data()));
202
203
204
205
206
207
    QVERIFY(testView.data());
    model->attachView(testView.data());

}

// TODO: this need to e updated for states
208
void tst_TestCore::loadEmptyCoreModel()
209
210
211
212
213
214
{
    QFile file(":/fx/empty.qml");
    QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));

    QPlainTextEdit textEdit1;
    textEdit1.setPlainText(file.readAll());
215
    NotIndentingTextEditModifier modifier1(&textEdit1);
216

217
    QScopedPointer<Model> model1(Model::create("QtQuick.Item"));
218
219
220
221
222
223

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());

    QPlainTextEdit textEdit2;
224
    textEdit2.setPlainText("import QtQuick 1.1; Item{}");
225
    NotIndentingTextEditModifier modifier2(&textEdit2);
226

227
    QScopedPointer<Model> model2(Model::create("QtQuick.Item"));
228
229
230
231
232
233
234
235

    QScopedPointer<TestRewriterView> testRewriterView2(new TestRewriterView());
    testRewriterView2->setTextModifier(&modifier2);
    model2->attachView(testRewriterView2.data());

    QVERIFY(compareTree(testRewriterView1->rootModelNode(), testRewriterView2->rootModelNode()));
}

236
void tst_TestCore::testRewriterView()
237
238
239
{
    try {
        QPlainTextEdit textEdit;
240
        textEdit.setPlainText("import QtQuick 1.1;\n\nItem {\n}\n");
241
        NotIndentingTextEditModifier textModifier(&textEdit);
242

243
        QScopedPointer<Model> model(Model::create("QtQuick.Item"));
244
245
        QVERIFY(model.data());

246
        QScopedPointer<TestView> view(new TestView(model.data()));
247
248
249
250
251
252
253
254
255
        QVERIFY(view.data());
        model->attachView(view.data());

        ModelNode rootModelNode(view->rootModelNode());
        QVERIFY(rootModelNode.isValid());
        QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
        testRewriterView->setTextModifier(&textModifier);
        model->attachView(testRewriterView.data());

256
        ModelNode childNode(addNodeListChild(rootModelNode, "QtQuick.Rectangle", 1, 0, "data"));
257
258
259
        QVERIFY(childNode.isValid());
        childNode.setId("childNode");

260
        ModelNode childNode2(addNodeListChild(childNode, "QtQuick.Rectangle", 1, 0, "data"));
261
        childNode2.setId("childNode2");
262
        ModelNode childNode3(addNodeListChild(childNode2, "QtQuick.Rectangle", 1, 0, "data"));
263
        childNode3.setId("childNode3");
264
        ModelNode childNode4(addNodeListChild(childNode3, "QtQuick.Rectangle", 1, 0, "data"));
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
        childNode4.setId("childNode4");

        QVERIFY(childNode.isValid());
        QVERIFY(childNode2.isValid());
        QVERIFY(childNode3.isValid());
        QVERIFY(childNode4.isValid());

        testRewriterView->setModificationGroupActive(true);

        childNode.destroy();

        QVERIFY(!childNode.isValid());
        QVERIFY(!childNode2.isValid());
        QVERIFY(!childNode3.isValid());
        QVERIFY(!childNode4.isValid());

        QVERIFY(testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode));
        QVERIFY(!testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode2));
        QVERIFY(!testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode3));
        QVERIFY(!testRewriterView->modelToTextMerger()->isNodeScheduledForRemoval(childNode4));

        QVERIFY(!rootModelNode.hasProperty(QLatin1String("data")));

        testRewriterView->modelToTextMerger()->applyChanges();

290
        childNode = addNodeListChild(rootModelNode, "QtQuick.Rectangle", 1, 0, "data");
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
        QVERIFY(testRewriterView->modelToTextMerger()->isNodeScheduledForAddition(childNode));

        testRewriterView->modelToTextMerger()->applyChanges();

        childNode.variantProperty("x") = 70;
        childNode.variantProperty("y") = 90;

        QCOMPARE(testRewriterView->modelToTextMerger()->findAddedVariantProperty(childNode.variantProperty("x")).value(), QVariant(70));
        QCOMPARE(testRewriterView->modelToTextMerger()->findAddedVariantProperty(childNode.variantProperty("y")).value(), QVariant(90));

        model->detachView(testRewriterView.data());
    } catch (Exception &e) {
        QFAIL(qPrintable(e.description()));
    }
}

307
void tst_TestCore::testRewriterErrors()
308
309
{
    QPlainTextEdit textEdit;
310
    textEdit.setPlainText("import QtQuick 1.1;\n\nItem {\n}\n");
311
    NotIndentingTextEditModifier textModifier(&textEdit);
312

313
    QScopedPointer<Model> model(Model::create("QtQuick.Item"));
314
315
    QVERIFY(model.data());

316
    QScopedPointer<TestView> view(new TestView(model.data()));
317
318
319
320
321
322
323
324
325
326
    QVERIFY(view.data());
    model->attachView(view.data());

    ModelNode rootModelNode(view->rootModelNode());
    QVERIFY(rootModelNode.isValid());
    QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
    testRewriterView->setTextModifier(&textModifier);
    model->attachView(testRewriterView.data());

    QVERIFY(testRewriterView->errors().isEmpty());
327
    textEdit.setPlainText("import QtQuick 1.1;\nRectangle {\ntest: blah\n}\n");
328
329
    QVERIFY(!testRewriterView->errors().isEmpty());

330
    textEdit.setPlainText("import QtQuick 1.1;\n\nItem {\n}\n");
331
332
333
    QVERIFY(testRewriterView->errors().isEmpty());
}

334
void tst_TestCore::saveEmptyCoreModel()
335
{
336
    QList<QDeclarativeError> errors;
337
338
339
340
341
    QFile file(":/fx/empty.qml");
    QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));

    QPlainTextEdit textEdit1;
    textEdit1.setPlainText(file.readAll());
342
    NotIndentingTextEditModifier modifier1(&textEdit1);
343

344
    QScopedPointer<Model> model1(Model::create("QtQuick.Item"));
345
346
347
348
349
350
351
352
353
354
355

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());


    QBuffer buffer;
    buffer.open(QIODevice::ReadWrite | QIODevice::Text);
    modifier1.save(&buffer);

    QPlainTextEdit textEdit2;
356
    textEdit2.setPlainText("import QtQuick 1.1; Item{}");
357
    NotIndentingTextEditModifier modifier2(&textEdit2);
358

359
    QScopedPointer<Model> model2(Model::create("QtQuick.Item"));
360
361
362
363
364
365
366
367
368

    QScopedPointer<TestRewriterView> testRewriterView2(new TestRewriterView());
    testRewriterView2->setTextModifier(&modifier2);
    model2->attachView(testRewriterView2.data());

    QVERIFY(compareTree(testRewriterView1->rootModelNode(), testRewriterView2->rootModelNode()));

}

369
void tst_TestCore::loadAttributesInCoreModel()
370
{
371
    QList<QDeclarativeError> errors;
372
373
374
375
376
    QFile file(":/fx/attributes.qml");
    QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));

    QPlainTextEdit textEdit1;
    textEdit1.setPlainText(file.readAll());
377
    NotIndentingTextEditModifier modifier1(&textEdit1);
378

379
    QScopedPointer<Model> model1(Model::create("QtQuick.Item"));
380
381
382
383
384
385

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());

    QPlainTextEdit textEdit2;
386
    textEdit2.setPlainText("import QtQuick 1.1; Item{}");
387
    NotIndentingTextEditModifier modifier2(&textEdit2);
388

389
    QScopedPointer<Model> model2(Model::create("QtQuick.Item"));
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404

    QScopedPointer<TestRewriterView> testRewriterView2(new TestRewriterView());
    testRewriterView2->setTextModifier(&modifier2);
    model2->attachView(testRewriterView2.data());

    ModelNode rootModelNode = testRewriterView2->rootModelNode();

    rootModelNode.setId("theItem");
    rootModelNode.variantProperty("x").setValue(QVariant(300));
    rootModelNode.variantProperty("visible").setValue(true);
    rootModelNode.variantProperty("scale").setValue(0.5);

    QVERIFY(compareTree(testRewriterView1->rootModelNode(), testRewriterView2->rootModelNode()));
}

405
void tst_TestCore::saveAttributesInCoreModel()
406
407
408
409
410
411
{
    QFile file(":/fx/attributes.qml");
    QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));

    QPlainTextEdit textEdit1;
    textEdit1.setPlainText(file.readAll());
412
    NotIndentingTextEditModifier modifier1(&textEdit1);
413

414
    QScopedPointer<Model> model1(Model::create("QtQuick.Item"));
415
416
417
418
419
420
421
422
423
424
425
426
427

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());

    QVERIFY(testRewriterView1->errors().isEmpty());

    QBuffer buffer;
    buffer.open(QIODevice::ReadWrite | QIODevice::Text);
    modifier1.save(&buffer);

    QPlainTextEdit textEdit2;
    textEdit2.setPlainText(buffer.data());
428
    NotIndentingTextEditModifier modifier2(&textEdit2);
429

430
    QScopedPointer<Model> model2(Model::create("QtQuick.Item"));
431
432
433
434
435
436
437
438
439
440

    QScopedPointer<TestRewriterView> testRewriterView2(new TestRewriterView());
    testRewriterView2->setTextModifier(&modifier2);
    model2->attachView(testRewriterView2.data());

    QVERIFY(testRewriterView2->errors().isEmpty());

    QVERIFY(compareTree(testRewriterView1->rootModelNode(), testRewriterView2->rootModelNode()));
}

441
void tst_TestCore::testModelCreateRect()
442
443
444
{
     try {

445
    QScopedPointer<Model> model(createModel("QtQuick.Item"));
446
447
    QVERIFY(model.data());

448
    QScopedPointer<TestView> view(new TestView(model.data()));
449
450
451
452
    QVERIFY(view.data());
    model->attachView(view.data());

    QVERIFY(view->rootModelNode().isValid());
453
    ModelNode childNode = addNodeListChild(view->rootModelNode(), "QtQuick.Rectangle", 1, 0, "data");
454
455
456
457
458
459
460
    QVERIFY(childNode.isValid());
    QVERIFY(view->rootModelNode().allDirectSubModelNodes().contains(childNode));
    QVERIFY(childNode.parentProperty().parentModelNode() == view->rootModelNode());
    QCOMPARE(childNode.simplifiedTypeName(), QString("Rectangle"));

    QVERIFY(childNode.id().isEmpty());

461
462
    childNode.setId("rect01");
    QCOMPARE(childNode.id(), QString("rect01"));
463
464
465
466
467

    childNode.variantProperty("x") = 100;
    childNode.variantProperty("y") = 100;
    childNode.variantProperty("width") = 100;
    childNode.variantProperty("height") = 100;
468

469
470
471
    QCOMPARE(childNode.propertyNames().count(), 4);
    QCOMPARE(childNode.variantProperty("scale").value(), QVariant());

Thomas Hartmann's avatar
Thomas Hartmann committed
472
     } catch (Exception &) {
473
474
475
476
477
        QFAIL("Exception thrown");
    }

}

478
void tst_TestCore::testRewriterDynamicProperties()
479
{
480
    const QLatin1String qmlString("\n"
481
                                  "import QtQuick 1.1\n"
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
                                  "\n"
                                  "Rectangle {\n"
                                  "  property int i\n"
                                  "  property int ii: 1\n"
                                  "  property bool b\n"
                                  "  property bool bb: true\n"
                                  "  property double d\n"
                                  "  property double dd: 1.1\n"
                                  "  property real r\n"
                                  "  property real rr: 1.1\n"
                                  "  property string s\n"
                                  "  property string ss: \"hello\"\n"
                                  "  property url u\n"
                                  "  property url uu: \"www\"\n"
                                  "  property color c\n"
                                  "  property color cc: \"#ffffff\"\n"
                                  "  property date t\n"
                                  "  property date tt: \"2000-03-20\"\n"
Kai Koehne's avatar
Kai Koehne committed
500
501
                                  "  property variant v\n"
                                  "  property variant vv: \"Hello\"\n"
502
                                  "}");
503
504

    QPlainTextEdit textEdit1;
505
    textEdit1.setPlainText(qmlString);
506
    NotIndentingTextEditModifier modifier1(&textEdit1);
507

508
    QScopedPointer<Model> model1(Model::create("QtQuick.Item"));
509
510
511
512
513

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());

514
    QVERIFY(testRewriterView1->errors().isEmpty());
515

516
517
518
519
    //
    // text2model
    //
    ModelNode rootModelNode = testRewriterView1->rootModelNode();
Marco Bubke's avatar
Marco Bubke committed
520
    QCOMPARE(rootModelNode.properties().count(), 18);
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
    QVERIFY(rootModelNode.hasVariantProperty("i"));
    QCOMPARE(rootModelNode.variantProperty("i").dynamicTypeName(), QString("int"));
    QCOMPARE(rootModelNode.variantProperty("i").value().type(), QVariant::Int);
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("i").value().toInt(), 0);

    QVERIFY(rootModelNode.hasVariantProperty("ii"));
    QCOMPARE(rootModelNode.variantProperty("ii").dynamicTypeName(), QString("int"));
    QCOMPARE(rootModelNode.variantProperty("ii").value().type(), QVariant::Int);
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("ii").value().toInt(), 1);

    QVERIFY(rootModelNode.hasVariantProperty("b"));
    QCOMPARE(rootModelNode.variantProperty("b").dynamicTypeName(), QString("bool"));
    QCOMPARE(rootModelNode.variantProperty("b").value().type(), QVariant::Bool);
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("b").value().toBool(), false);

    QVERIFY(rootModelNode.hasVariantProperty("bb"));
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("bb").value().toBool(), true);

    QVERIFY(rootModelNode.hasVariantProperty("d"));
    QCOMPARE(rootModelNode.variantProperty("d").dynamicTypeName(), QString("double"));
    QCOMPARE(rootModelNode.variantProperty("d").value().type(), QVariant::Double);
542
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("d").value().toDouble(), 0.0);
543
544
545
546
547

    QVERIFY(rootModelNode.hasVariantProperty("dd"));
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("dd").value().toDouble(), 1.1);

    QVERIFY(rootModelNode.hasVariantProperty("r"));
548
    QCOMPARE(rootModelNode.variantProperty("r").dynamicTypeName(), QString("real"));
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
    QCOMPARE(rootModelNode.variantProperty("r").value().type(), QVariant::Double);
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("r").value().toDouble(), 0.0);

    QVERIFY(rootModelNode.hasVariantProperty("rr"));
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("rr").value().toDouble(), 1.1);

    QVERIFY(rootModelNode.hasVariantProperty("s"));
    QCOMPARE(rootModelNode.variantProperty("s").dynamicTypeName(), QString("string"));
    QCOMPARE(rootModelNode.variantProperty("s").value().type(), QVariant::String);
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("s").value().toString(), QString());

    QVERIFY(rootModelNode.hasVariantProperty("ss"));
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("ss").value().toString(), QString("hello"));

    QVERIFY(rootModelNode.hasVariantProperty("u"));
    QCOMPARE(rootModelNode.variantProperty("u").dynamicTypeName(), QString("url"));
    QCOMPARE(rootModelNode.variantProperty("u").value().type(), QVariant::Url);
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("u").value().toUrl(), QUrl());

    QVERIFY(rootModelNode.hasVariantProperty("uu"));
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("uu").value().toUrl(), QUrl("www"));

    QVERIFY(rootModelNode.hasVariantProperty("c"));
    QCOMPARE(rootModelNode.variantProperty("c").dynamicTypeName(), QString("color"));
    QCOMPARE(rootModelNode.variantProperty("c").value().type(), QVariant::Color);
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("c").value().value<QColor>(), QColor());

    QVERIFY(rootModelNode.hasVariantProperty("cc"));
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("cc").value().value<QColor>(), QColor(255, 255, 255));

    QVERIFY(rootModelNode.hasVariantProperty("t"));
    QCOMPARE(rootModelNode.variantProperty("t").dynamicTypeName(), QString("date"));
581
    QCOMPARE(rootModelNode.variantProperty("t").value().type(), QVariant::Date);
582
583
584
585
586
587
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("t").value().value<QDate>(), QDate());

    QVERIFY(rootModelNode.hasVariantProperty("tt"));
    QCOMPARE(testRewriterView1->rootModelNode().variantProperty("tt").value().value<QDate>(), QDate(2000, 3, 20));

    QVERIFY(rootModelNode.hasVariantProperty("v"));
Kai Koehne's avatar
Kai Koehne committed
588
    QCOMPARE(rootModelNode.variantProperty("v").dynamicTypeName(), QString("variant"));
589
590
    const int type = rootModelNode.variantProperty("v").value().type();
    QCOMPARE(type, QMetaType::type("QVariant"));
591
592

    QVERIFY(rootModelNode.hasVariantProperty("vv"));
593
594
    const QString inThere = testRewriterView1->rootModelNode().variantProperty("vv").value().value<QString>();
    QCOMPARE(inThere, QString("Hello"));
595
596
597

    // test model2text
//    QPlainTextEdit textEdit2;
598
//    textEdit2.setPlainText("import QtQuick 1.1; Item{}");
599
600
//    NotIndentingTextEditModifier modifier2(&textEdit2);
//
601
//    QScopedPointer<Model> model2(Model::create("QtQuick.Item"));
602
603
604
605
606
607
608
609
//
//    QScopedPointer<TestRewriterView> testRewriterView2(new TestRewriterView());
//    testRewriterView2->setTextModifier(&modifier2);
//    model2->attachView(testRewriterView2.data());
//
//    testRewriterView2->rootModelNode().variantProperty("pushed").setDynamicTypeNameAndValue("bool", QVariant(false));
//
//    QVERIFY(compareTree(testRewriterView1->rootModelNode(), testRewriterView2->rootModelNode()));
610
611
}

612
void tst_TestCore::testRewriterGroupedProperties()
613
614
{
    const QLatin1String qmlString("\n"
615
                                  "import QtQuick 1.1\n"
616
617
618
619
620
621
                                  "\n"
                                  "Text {\n"
                                  "  font {\n"
                                  "    pointSize: 10\n"
                                  "    underline: true\n"
                                  "  }\n"
622
                                  "}\n");
623

624
625
626
    QPlainTextEdit textEdit;
    textEdit.setPlainText(qmlString);
    NotIndentingTextEditModifier modifier1(&textEdit);
627

628
    QScopedPointer<Model> model1(Model::create("QtQuick.Text"));
629
630
631
632
633
634
635
636
637
638
639
640
641

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());

    QVERIFY(testRewriterView1->errors().isEmpty());

    //
    // text2model
    //
    ModelNode rootModelNode = testRewriterView1->rootModelNode();
    QCOMPARE(rootModelNode.property(QLatin1String("font.pointSize")).toVariantProperty().value().toDouble(), 10.0);
    QCOMPARE(rootModelNode.property(QLatin1String("font.underline")).toVariantProperty().value().toBool(), true);
642
643
644
645
646
647
648
649
650
651

    rootModelNode.removeProperty(QLatin1String("font.underline"));
    QCOMPARE(rootModelNode.property(QLatin1String("font.pointSize")).toVariantProperty().value().toDouble(), 10.0);
    QVERIFY(!rootModelNode.hasProperty(QLatin1String("font.underline")));

    rootModelNode.variantProperty(QLatin1String("font.pointSize")).setValue(20.0);
    QCOMPARE(rootModelNode.property(QLatin1String("font.pointSize")).toVariantProperty().value().toDouble(), 20.0);

    rootModelNode.removeProperty(QLatin1String("font.pointSize"));
    const QLatin1String expected("\n"
652
                                 "import QtQuick 1.1\n"
653
654
655
656
657
                                 "\n"
                                 "Text {\n"
                                 "}\n");

    QCOMPARE(textEdit.toPlainText(), expected);
658
659
}

660
void tst_TestCore::testRewriterPreserveOrder()
661
662
{
    const QLatin1String qmlString1("\n"
663
        "import QtQuick 1.1\n"
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
        "\n"
        "Rectangle {\n"
            "width: 640\n"
            "height: 480\n"
            "\n"
            "states: [\n"
                "State {\n"
                    "name: \"State1\"\n"
                "}\n"
            "]\n"
            "\n"
            "Rectangle {\n"
                "id: rectangle1\n"
                "x: 18\n"
                "y: 19\n"
                "width: 100\n"
                "height: 100\n"
            "}\n"
        "}\n");
    const QLatin1String qmlString2("\n"
684
        "import QtQuick 1.1\n"
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
        "\n"
        "Rectangle {\n"
            "width: 640\n"
            "height: 480\n"
            "\n"
            "Rectangle {\n"
                "id: rectangle1\n"
                "x: 18\n"
                "y: 19\n"
                "width: 100\n"
                "height: 100\n"
            "}\n"
            "states: [\n"
                "State {\n"
                    "name: \"State1\"\n"
                "}\n"
            "]\n"
            "\n"
        "}\n");

        {
        QPlainTextEdit textEdit;
        textEdit.setPlainText(qmlString2);
        NotIndentingTextEditModifier modifier(&textEdit);

710
        QScopedPointer<Model> model(Model::create("QtQuick.Text"));
711
712
713
714
715
716
717
718
719
720
721
722

        QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
        testRewriterView->setTextModifier(&modifier);
        model->attachView(testRewriterView.data());

        QVERIFY(testRewriterView->errors().isEmpty());

        ModelNode rootModelNode = testRewriterView->rootModelNode();
        QVERIFY(rootModelNode.isValid());

        RewriterTransaction transaction = testRewriterView->beginRewriterTransaction();

723
        ModelNode newModelNode = testRewriterView->createModelNode("QtQuick.Rectangle", 1, 0);
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744

        newModelNode.setParentProperty(rootModelNode.nodeAbstractProperty("data"));

        newModelNode.setId("rectangle2");
        QCOMPARE(newModelNode.id(), QString("rectangle2"));

        newModelNode.variantProperty("x") = 10;
        newModelNode.variantProperty("y") = 10;
        newModelNode.variantProperty("width") = 100;
        newModelNode.variantProperty("height") = 100;

        transaction.commit();

        QCOMPARE(newModelNode.id(), QString("rectangle2"));
    }

    {
        QPlainTextEdit textEdit;
        textEdit.setPlainText(qmlString1);
        NotIndentingTextEditModifier modifier(&textEdit);

745
        QScopedPointer<Model> model(Model::create("QtQuick.Text"));
746
747
748
749
750
751
752
753
754
755
756
757

        QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
        testRewriterView->setTextModifier(&modifier);
        model->attachView(testRewriterView.data());

        QVERIFY(testRewriterView->errors().isEmpty());

        ModelNode rootModelNode = testRewriterView->rootModelNode();
        QVERIFY(rootModelNode.isValid());

        RewriterTransaction transaction = testRewriterView->beginRewriterTransaction();

758
        ModelNode newModelNode = testRewriterView->createModelNode("QtQuick.Rectangle", 1, 0);
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775

        newModelNode.setParentProperty(rootModelNode.nodeAbstractProperty("data"));

        newModelNode.setId("rectangle2");
        QCOMPARE(newModelNode.id(), QString("rectangle2"));

        newModelNode.variantProperty("x") = 10;
        newModelNode.variantProperty("y") = 10;
        newModelNode.variantProperty("width") = 100;
        newModelNode.variantProperty("height") = 100;

        transaction.commit();

        QCOMPARE(newModelNode.id(), QString("rectangle2"));
    }
}

776
void tst_TestCore::testRewriterActionCompression()
777
778
{
    const QLatin1String qmlString("\n"
779
                                  "import QtQuick 1.1\n"
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
                                  "\n"
                                  "Rectangle {\n"
                                  "  id: root\n"
                                  "  Rectangle {\n"
                                  "    id: rect1\n"
                                  "    x: 10\n"
                                  "    y: 10\n"
                                  "  }\n"
                                  "  Rectangle {\n"
                                  "    id: rect2\n"
                                  "    x: 10\n"
                                  "    y: 10\n"
                                  "  }\n"
                                  "}\n");

    QPlainTextEdit textEdit;
    textEdit.setPlainText(qmlString);
    NotIndentingTextEditModifier modifier1(&textEdit);

799
    QScopedPointer<Model> model1(Model::create("QtQuick.Rectangle"));
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824

    QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
    testRewriterView->setTextModifier(&modifier1);
    model1->attachView(testRewriterView.data());

    QVERIFY(testRewriterView->errors().isEmpty());

    ModelNode rootModelNode = testRewriterView->rootModelNode();
    ModelNode rect1 = rootModelNode.property(QLatin1String("data")).toNodeListProperty().toModelNodeList().at(0);
    ModelNode rect2 = rootModelNode.property(QLatin1String("data")).toNodeListProperty().toModelNodeList().at(1);

    QVERIFY(rect1.isValid());
    QVERIFY(rect2.isValid());

    RewriterTransaction transaction = testRewriterView->beginRewriterTransaction();
    rect1.nodeListProperty(QLatin1String("data")).reparentHere(rect2);
    rect2.variantProperty(QLatin1String("x")).setValue(1.0);
    rect2.variantProperty(QLatin1String("y")).setValue(1.0);

    rootModelNode.nodeListProperty(QLatin1String("data")).reparentHere(rect2);
    rect2.variantProperty(QLatin1String("x")).setValue(9.0);
    rect2.variantProperty(QLatin1String("y")).setValue(9.0);
    transaction.commit();

    const QLatin1String expected("\n"
825
                                 "import QtQuick 1.1\n"
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
                                 "\n"
                                 "Rectangle {\n"
                                 "  id: root\n"
                                 "  Rectangle {\n"
                                 "    id: rect1\n"
                                 "    x: 10\n"
                                 "    y: 10\n"
                                 "  }\n"
                                 "  Rectangle {\n"
                                 "    id: rect2\n"
                                 "    x: 9\n"
                                 "    y: 9\n"
                                 "  }\n"
                                 "}\n");
    QCOMPARE(textEdit.toPlainText(), expected);
}

843
void tst_TestCore::testRewriterImports()
844
845
846
847
848
849
850
851
852
{
    QString fileName = QString(QTCREATORDIR) + "/tests/auto/qml/qmldesigner/data/fx/imports.qml";
    QFile file(fileName);
    QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));

    QPlainTextEdit textEdit;
    textEdit.setPlainText(file.readAll());
    NotIndentingTextEditModifier modifier(&textEdit);

853
    QScopedPointer<Model> model(Model::create("QtQuick.Item"));
854
855
856
857
858
859
860
861
862
863
    model->setFileUrl(QUrl::fromLocalFile(fileName));

    QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
    testRewriterView->setTextModifier(&modifier);
    model->attachView(testRewriterView.data());

    QVERIFY(testRewriterView->errors().isEmpty());

    QVERIFY(model->imports().size() == 3);

864
    // import QtQuick 1.1
865
866
    Import import = model->imports().at(0);
    QVERIFY(import.isLibraryImport());
867
    QCOMPARE(import.url(), QString("QtQuick"));
868
    QVERIFY(import.hasVersion());
869
    QCOMPARE(import.version(), QString("1.0"));
870
871
872
873
874
875
876
877
878
    QVERIFY(!import.hasAlias());

    // import "subitems"
    import = model->imports().at(1);
    QVERIFY(import.isFileImport());
    QCOMPARE(import.file(), QString("subitems"));
    QVERIFY(!import.hasVersion());
    QVERIFY(!import.hasAlias());

879
    // import QtWebKit 1.0 as Web
880
881
    import = model->imports().at(2);
    QVERIFY(import.isLibraryImport());
882
    QCOMPARE(import.url(), QString("QtWebKit"));
883
884
885
886
887
888
    QVERIFY(import.hasVersion());
    QCOMPARE(import.version(), QString("1.0"));
    QVERIFY(import.hasAlias());
    QCOMPARE(import.alias(), QString("Web"));
}

889
void tst_TestCore::testRewriterChangeImports()
890
891
{
    const QLatin1String qmlString("\n"
892
                                  "import QtQuick 1.1\n"
893
894
895
896
897
898
899
                                  "\n"
                                  "Rectangle {}\n");

    QPlainTextEdit textEdit;
    textEdit.setPlainText(qmlString);
    NotIndentingTextEditModifier modifier(&textEdit);

900
    QScopedPointer<Model> model(Model::create("QtQuick.Rectangle"));
901
902
903
904
905
906
907
908
909
910

    QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView(0, RewriterView::Amend));
    testRewriterView->setTextModifier(&modifier);
    model->attachView(testRewriterView.data());

    QVERIFY(testRewriterView->errors().isEmpty());

    //
    // Add / Remove an import in the model
    //
911
    Import webkitImport = Import::createLibraryImport("QtWebKit", "1.0");
912
913
914
915
916

    QList<Import> importList;
    importList << webkitImport;

    model->changeImports(importList, QList<Import>());
917
918

    const QLatin1String qmlWithImport("\n"
919
                                 "import QtQuick 1.1\n"
920
                                 "import QtWebKit 1.0\n"
921
922
923
924
                                 "\n"
                                 "Rectangle {}\n");
    QCOMPARE(textEdit.toPlainText(), qmlWithImport);

925
    model->changeImports(QList<Import>(), importList);
926
927

    QCOMPARE(model->imports().size(), 1);
928
    QCOMPARE(model->imports().first(), Import::createLibraryImport("QtQuick", "1.1"));
929
930
931
932
933
934
935

    QCOMPARE(textEdit.toPlainText(), qmlString);


    //
    // Add / Remove an import in the model (with alias)
    //
936
937
938
939

    Import webkitImportAlias = Import::createLibraryImport("QtWebKit", "1.0", "Web");

    model->changeImports(QList<Import>() << webkitImportAlias, QList<Import>() <<  webkitImport);
940
941

    const QLatin1String qmlWithAliasImport("\n"
942
                                 "import QtQuick 1.1\n"
943
                                 "import QtWebKit 1.0 as Web\n"
944
945
946
947
                                 "\n"
                                 "Rectangle {}\n");
    QCOMPARE(textEdit.toPlainText(), qmlWithAliasImport);

948
949
    model->changeImports(QList<Import>(), QList<Import>() << webkitImportAlias);
    QCOMPARE(model->imports().first(), Import::createLibraryImport("QtQuick", "1.1"));
950
951
952
953
954
955
956
957

    QCOMPARE(textEdit.toPlainText(), qmlString);

    //
    // Add / Remove an import in text
    //
    textEdit.setPlainText(qmlWithImport);
    QCOMPARE(model->imports().size(), 2);
958
    QCOMPARE(model->imports().first(), Import::createLibraryImport("QtQuick", "1.1"));
959
    QCOMPARE(model->imports().last(), Import::createLibraryImport("QtWebKit", "1.0"));
960
961
962

    textEdit.setPlainText(qmlWithAliasImport);
    QCOMPARE(model->imports().size(), 2);
963
    QCOMPARE(model->imports().first(), Import::createLibraryImport("QtQuick", "1.1"));
964
    QCOMPARE(model->imports().last(), Import::createLibraryImport("QtWebKit", "1.0", "Web"));
965
966
967

    textEdit.setPlainText(qmlString);
    QCOMPARE(model->imports().size(), 1);
968
    QCOMPARE(model->imports().first(), Import::createLibraryImport("QtQuick", "1.1"));
969
970
}

971
void tst_TestCore::testRewriterForGradientMagic()
972
973
{
    const QLatin1String qmlString("\n"
974
                                  "import QtQuick 1.1\n"
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
                                  "\n"
                                  "Rectangle {\n"
                                  "    id: root\n"
                                  "    x: 10;\n"
                                  "    y: 10;\n"
                                  "    Rectangle {\n"
                                  "        id: rectangle1\n"
                                  "        x: 10;\n"
                                  "        y: 10;\n"
                                  "    }\n"
                                  "    Rectangle {\n"
                                  "        id: rectangle2\n"
                                  "        x: 100;\n"
                                  "        y: 100;\n"
                                  "        anchors.fill: root\n"
                                  "    }\n"
                                  "    Rectangle {\n"
                                  "        id: rectangle3\n"
                                  "        x: 140;\n"
                                  "        y: 180;\n"
                                  "        gradient: Gradient {\n"
                                  "             GradientStop {\n"
                                  "                 position: 0\n"
                                  "                 color: \"white\"\n"
                                  "             }\n"
                                  "             GradientStop {\n"
                                  "                  position: 1\n"
                                  "                  color: \"black\"\n"
                                  "             }\n"
                                  "        }\n"
                                  "    }\n"
                                  "}");

    QPlainTextEdit textEdit;
    textEdit.setPlainText(qmlString);
    NotIndentingTextEditModifier modifier(&textEdit);

1012
    QScopedPointer<Model> model(Model::create("QtQuick.Text"));
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027

    QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
    testRewriterView->setTextModifier(&modifier);
    model->attachView(testRewriterView.data());

    QVERIFY(testRewriterView->errors().isEmpty());

    ModelNode rootModelNode = testRewriterView->rootModelNode();
    QVERIFY(rootModelNode.isValid());

    ModelNode myRect = testRewriterView->modelNodeForId(QLatin1String("rectangle3"));
    QVERIFY(myRect.isValid());
    myRect.variantProperty("rotation") = QVariant(45);
    QVERIFY(myRect.isValid());

1028
    QScopedPointer<Model> model1(Model::create("QtQuick.Item", 1, 1));
1029
1030
    QVERIFY(model1.data());

1031
    QScopedPointer<TestView> view1(new TestView(model1.data()));
1032
1033
1034
1035
    model1->attachView(view1.data());

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    QPlainTextEdit textEdit1;
1036
    textEdit1.setPlainText("import QtQuick 1.1; Item {}");
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
    NotIndentingTextEditModifier modifier1(&textEdit1);

    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());

    QVERIFY(testRewriterView1->errors().isEmpty());

    RewriterTransaction transaction(view1->beginRewriterTransaction());

    ModelMerger merger(view1.data());

    QVERIFY(myRect.isValid());
    merger.replaceModel(myRect);
    transaction.commit();
}

1053
void tst_TestCore::loadSubItems()
1054
{
1055
    QFile file(QString(QTCREATORDIR) + "/tests/auto/qml/qmldesigner/data/fx/topitem.qml");
1056
1057
1058
1059
    QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));

    QPlainTextEdit textEdit1;
    textEdit1.setPlainText(file.readAll());
1060
    NotIndentingTextEditModifier modifier1(&textEdit1);
1061

1062
    QScopedPointer<Model> model1(Model::create("QtQuick.Item"));
1063
1064
1065
1066
1067
1068

    QScopedPointer<TestRewriterView> testRewriterView1(new TestRewriterView());
    testRewriterView1->setTextModifier(&modifier1);
    model1->attachView(testRewriterView1.data());
}

1069
void tst_TestCore::createInvalidCoreModel()
1070
{
1071
    QScopedPointer<Model> invalidModel(createModel("ItemSUX"));
1072
1073
    //QVERIFY(!invalidModel.data()); //#no direct ype checking in model atm

1074
    QScopedPointer<Model> invalidModel2(createModel("InvalidNode"));
1075
1076
1077
    //QVERIFY(!invalidModel2.data());
}

1078
void tst_TestCore::testModelCreateSubNode()
1079
{
1080
    QScopedPointer<Model> model(createModel("QtQuick.Item"));
1081
1082
    QVERIFY(model.data());

1083
    QScopedPointer<TestView> view(new TestView(model.data()));
1084
1085
1086
1087
1088
1089
1090
1091
    QVERIFY(view.data());
    model->attachView(view.data());

    QList<TestView::MethodCall> expectedCalls;
    expectedCalls << TestView::MethodCall("modelAttached", QStringList() << QString::number(reinterpret_cast<long>(model.data())));
    QCOMPARE(view->methodCalls(), expectedCalls);

    QVERIFY(view->rootModelNode().isValid());
1092
    ModelNode childNode = addNodeListChild(view->rootModelNode(), "QtQuick.Rectangle", 1, 0, "data");
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
    QVERIFY(childNode.isValid());
    QVERIFY(view->rootModelNode().allDirectSubModelNodes().contains(childNode));
    QVERIFY(childNode.parentProperty().parentModelNode() == view->rootModelNode());
    QCOMPARE(childNode.simplifiedTypeName(), QString("Rectangle"));

    expectedCalls << TestView::MethodCall("nodeCreated", QStringList() << "");
    expectedCalls << TestView::MethodCall("nodeReparented", QStringList() << "" << "data" << "" << "PropertiesAdded");
    QCOMPARE(view->methodCalls(), expectedCalls);

    QVERIFY(childNode.id().isEmpty());
1103
1104
    childNode.setId("blah");
    QCOMPARE(childNode.id(), QString("blah"));
1105

1106
    expectedCalls << TestView::MethodCall("nodeIdChanged", QStringList() << "blah" << "blah" << "");
1107
1108
1109
1110
1111
1112
1113
1114
1115
    QCOMPARE(view->methodCalls(), expectedCalls);

    try {
        childNode.setId("invalid id");
        QFAIL("Setting an invalid id does not throw an excxeption");
    } catch (Exception &exception) {
        QCOMPARE(exception.type(), QString("InvalidIdException"));
    }

1116
    QCOMPARE(childNode.id(), QString("blah"));
1117
    QCOMPARE(view->methodCalls(), expectedCalls);
1118
1119
1120

    childNode.setId(QString());
    QVERIFY(childNode.id().isEmpty());
1121
1122
1123
}


1124
void tst_TestCore::testTypicalRewriterOperations()
1125
{
1126
    QScopedPointer<Model> model(createModel("QtQuick.Item"));
1127
1128
    QVERIFY(model.data());

1129
    QScopedPointer<TestView> view(new TestView(model.data()));
1130
1131
1132
1133
1134
1135
    QVERIFY(view.data());
    model->attachView(view.data());

    ModelNode rootModelNode = view->rootModelNode();
    QCOMPARE(rootModelNode.allDirectSubModelNodes().count(), 0);

1136
1137
1138
    QVERIFY(rootModelNode.property("x").isValid());
    QVERIFY(!rootModelNode.property("x").isVariantProperty());
    QVERIFY(!rootModelNode.property("x").isBindingProperty());
1139

1140
1141
    QVERIFY(rootModelNode.variantProperty("x").isValid());
    QVERIFY(!rootModelNode.hasProperty("x"));
1142

1143
    rootModelNode.variantProperty("x") = 70;
1144

1145
1146
1147
    QVERIFY(rootModelNode.hasProperty("x"));
    QVERIFY(rootModelNode.property("x").isVariantProperty());
    QCOMPARE(rootModelNode.variantProperty("x").value(), QVariant(70));
1148

1149
1150
1151
    rootModelNode.bindingProperty("x") = "parent.x";
    QVERIFY(!rootModelNode.property("x").isVariantProperty());
    QVERIFY(rootModelNode.property("x").isBindingProperty());
1152

1153
    QCOMPARE(rootModelNode.bindingProperty("x").expression(), QString("parent.x"));
1154

1155
1156
1157
1158
1159
1160
    ModelNode childNode(addNodeListChild(rootModelNode, "QtQuick.Rectangle", 1 ,0, "data"));
    rootModelNode.nodeListProperty("data").reparentHere(childNode);
    QCOMPARE(childNode.parentProperty(), rootModelNode.nodeAbstractProperty("data"));
    QVERIFY(rootModelNode.property("data").isNodeAbstractProperty());
    QVERIFY(rootModelNode.property("data").isNodeListProperty());
    QVERIFY(!rootModelNode.property("data").isBindingProperty());
1161
    QVERIFY(childNode.parentProperty().isNodeListProperty());
1162
1163
    QCOMPARE(childNode, childNode.parentProperty().toNodeListProperty().toModelNodeList().first());
    QCOMPARE(rootModelNode, childNode.parentProperty().parentModelNode());
1164
    QCOMPARE(childNode.parentProperty().name(), QString("data"));
1165

1166
1167
1168
1169
    QVERIFY(!rootModelNode.property("x").isVariantProperty());
    rootModelNode.variantProperty("x") = 90;
    QVERIFY(rootModelNode.property("x").isVariantProperty());
    QCOMPARE(rootModelNode.variantProperty("x").value(), QVariant(90));
1170
1171
1172

}

1173
void tst_TestCore::testBasicStates()
1174
{
1175
    char qmlString[] = "import QtQuick 1.1\n"
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
                       "Rectangle {\n"
                       "id: root;\n"
                            "Rectangle {\n"
                                "id: rect1;\n"
                            "}\n"
                            "Rectangle {\n"
                                "id: rect2;\n"
                            "}\n"
                            "states: [\n"
                                "State {\n"
                                    "name: \"state1\"\n"
                                    "PropertyChanges {\n"
                                        "target: rect1\n"
                                    "}\n"
                                    "PropertyChanges {\n"
                                        "target: rect2\n"
                                    "}\n"
                                "}\n"
                                ","
                                "State {\n"
                                    "name: \"state2\"\n"
                                    "PropertyChanges {\n"
                                        "target: rect1\n"
                                    "}\n"
                                    "PropertyChanges {\n"
                                        "target: rect2;\n"
                                        "x: 10;\n"
                                    "}\n"
                                "}\n"
                            "]\n"
                       "}\n";

    Exception::setShouldAssert(true);

    QPlainTextEdit textEdit;
    textEdit.setPlainText(qmlString);
1212
    NotIndentingTextEditModifier textModifier(&textEdit);
1213

1214
    QScopedPointer<Model> model(Model::create("QtQuick.Item"));
1215
1216
    QVERIFY(model.data());

1217
    QScopedPointer<TestView> view(new TestView(model.data()));
1218
1219
1220
1221
1222
    QVERIFY(view.data());
    model->attachView(view.data());

    ModelNode rootModelNode(view->rootModelNode());
    QVERIFY(rootModelNode.isValid());
Marco Bubke's avatar
Marco Bubke committed
1223
    QCOMPARE(rootModelNode.type(), QString("QtQuick.Item"));
1224
1225
1226
1227
1228
    QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
    testRewriterView->setTextModifier(&textModifier);

    model->attachView(testRewriterView.data());
    QVERIFY(rootModelNode.isValid());
Marco Bubke's avatar
Marco Bubke committed
1229
    QCOMPARE(rootModelNode.type(), QString("QtQuick.Rectangle"));
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261

    QVERIFY(rootModelNode.hasProperty("data"));

    QVERIFY(rootModelNode.property("data").isNodeListProperty());

    QCOMPARE(rootModelNode.nodeListProperty("data").toModelNodeList().count(), 2);

    ModelNode rect1 = rootModelNode.nodeListProperty("data").toModelNodeList().first();
    ModelNode rect2 = rootModelNode.nodeListProperty("data").toModelNodeList().last();

    QVERIFY(QmlItemNode(rect1).isValid());
    QVERIFY(QmlItemNode(rect2).isValid());

    QVERIFY(QmlItemNode(rootModelNode).isValid());

    QCOMPARE(QmlItemNode(rootModelNode).states().allStates().count(), 2);
    QCOMPARE(QmlItemNode(rootModelNode).states().names().count(), 2);
    QCOMPARE(QmlItemNode(rootModelNode).states().names().first(), QString("state1"));
    QCOMPARE(QmlItemNode(rootModelNode).states().names().last(), QString("state2"));

    //
    // QmlModelState API tests
    //
    QmlModelState state1 = QmlItemNode(rootModelNode).states().state("state1");
    QmlModelState state2 = QmlItemNode(rootModelNode).states().state("state2");

    QVERIFY(state1.isValid());
    QVERIFY(state2.isValid());

    QCOMPARE(state1.propertyChanges().count(), 2);
    QCOMPARE(state2.propertyChanges().count(), 2);