diff options
author | Fawzi Mohamed <fawzi.mohamed@qt.io> | 2021-03-23 15:37:32 +0100 |
---|---|---|
committer | Fawzi Mohamed <fawzi.mohamed@qt.io> | 2021-06-05 00:07:48 +0200 |
commit | de3d65009adf3c7ce0be6da77ee74b0a2610c9c5 (patch) | |
tree | b9c03fc2b5e2c7845c4b4070c403eae66e5df3ef /tests/auto/qmldom | |
parent | 6cf15ad4e359223bb19c997f0dd279f9aea842d7 (diff) |
qmldom: writeOut, write reformatted Qml
Adding writeOut: support for reformatted Qml
- linewriter: write line by line with caching, callbacks,
SourceLoaction updating
- outwriter: write to line writer, and keep track of updated file
locations and reformatted ScriptExpressions
- reformatter: reformat javascript
Change-Id: I4bdc393fb2d9b5a3db944a850719c24ef8726d15
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qmldom')
24 files changed, 807 insertions, 0 deletions
diff --git a/tests/auto/qmldom/CMakeLists.txt b/tests/auto/qmldom/CMakeLists.txt index ebdf993038..36386cf821 100644 --- a/tests/auto/qmldom/CMakeLists.txt +++ b/tests/auto/qmldom/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(domitem) add_subdirectory(path) add_subdirectory(stringdumper) add_subdirectory(merging) +add_subdirectory(reformatter) add_subdirectory(combined) diff --git a/tests/auto/qmldom/combined/CMakeLists.txt b/tests/auto/qmldom/combined/CMakeLists.txt index ed2d492cdc..1eb7d7c790 100644 --- a/tests/auto/qmldom/combined/CMakeLists.txt +++ b/tests/auto/qmldom/combined/CMakeLists.txt @@ -16,6 +16,7 @@ qt_internal_add_test(tst_dom_all ../path/tst_qmldompath.h ../domitem/tst_qmldomitem.h ../merging/tst_dommerging.h + ../reformatter/tst_reformatter.h INCLUDE_DIRECTORIES .. DEFINES diff --git a/tests/auto/qmldom/combined/tst_dom_all.cpp b/tests/auto/qmldom/combined/tst_dom_all.cpp index 91ec70db83..c89792e482 100644 --- a/tests/auto/qmldom/combined/tst_dom_all.cpp +++ b/tests/auto/qmldom/combined/tst_dom_all.cpp @@ -40,6 +40,7 @@ #include "domitem/tst_qmldomitem.h" #include "merging/tst_dommerging.h" #include "path/tst_qmldompath.h" +#include "reformatter/tst_reformatter.h" int main(int argc, char *argv[]) { @@ -64,5 +65,9 @@ int main(int argc, char *argv[]) QQmlJS::Dom::TestDomMerging test; status |= QTest::qExec(&test, argc, argv); } + { + QQmlJS::Dom::TestReformatter test; + status |= QTest::qExec(&test, argc, argv); + } return status; } diff --git a/tests/auto/qmldom/domdata/reformatter/MyComponent.qml b/tests/auto/qmldom/domdata/reformatter/MyComponent.qml new file mode 100644 index 0000000000..e661503f12 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/MyComponent.qml @@ -0,0 +1,5 @@ +import QtQuick + +Rectangle { + text: "bla" +} diff --git a/tests/auto/qmldom/domdata/reformatter/commentedFile.qml b/tests/auto/qmldom/domdata/reformatter/commentedFile.qml new file mode 100644 index 0000000000..4db877dcd1 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/commentedFile.qml @@ -0,0 +1,31 @@ +// pre comment +import QtQuick 2.15 + +// pre item comment +/* multi +line */ // comment after multi line +Item { +// binding comment +a: {// header + +// before x() +// before x() +x() // after x +// before y = 8 + z + zz + +// before y = 8 + z + zz +y = 8 + +// before z +z + // after z +// before zz +zz - // after z + zz +/*before (a b)*/(/* before a */ a * /* after a */ b * /*after b*/ c) // after (a * b * c) + + a + b // comment + +// footer +} +// post binding comment +} +// footer file comment +/* second comment */ /* third comment */ diff --git a/tests/auto/qmldom/domdata/reformatter/commentedFileReformatted.qml b/tests/auto/qmldom/domdata/reformatter/commentedFileReformatted.qml new file mode 100644 index 0000000000..4125cbed2e --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/commentedFileReformatted.qml @@ -0,0 +1,31 @@ +// pre comment +import QtQuick 2.15 + +// pre item comment +/* multi +line */ // comment after multi line +Item { + // binding comment + a: { + // header + + // before x() + // before x() + x(); // after x + // before y = 8 + z + zz + + // before y = 8 + z + zz + y = 8 + + // before z + z + // after z + // before zz + zz - // after z + zz + /*before (a b)*/(/* before a */ a * /* after a */ b * /*after b*/ c); // after (a * b * c) + a + b; // comment + + // footer + } + // post binding comment +} +// footer file comment +/* second comment */ /* third comment */ diff --git a/tests/auto/qmldom/domdata/reformatter/commentedFileReformatted2.qml b/tests/auto/qmldom/domdata/reformatter/commentedFileReformatted2.qml new file mode 100644 index 0000000000..df090abd6c --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/commentedFileReformatted2.qml @@ -0,0 +1,31 @@ +// pre comment +import QtQuick 2.15 + +// pre item comment +/* multi +line */ // comment after multi line +Item { + // binding comment + a: { + // header + + // before x() + // before x() + x(); // after x + // before y = 8 + z + zz + + // before y = 8 + z + zz + y = 8 + + // before z + z + // after z + // before zz + zz - // after z + zz + /*before (a b)*/(/* before a */ a * /* after a */ b * /*after b*/ c); // after (a * b * c) + a + b; // comment + + // footer + } + // post binding comment +} +// footer file comment +/* second comment */ /* third comment */ diff --git a/tests/auto/qmldom/domdata/reformatter/file1.qml b/tests/auto/qmldom/domdata/reformatter/file1.qml new file mode 100644 index 0000000000..9df78103f1 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/file1.qml @@ -0,0 +1,42 @@ +pragma pippo +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { + visible: true + width: 640 + height: 480 + title: qsTr("Scroll") + + Rectangle { + anchors.fill: parent + + ListView { + width: parent.width + model: { + MySingleton.mySignal() + 20 + } + delegate: ItemDelegate { + id: root + text: "Item " + (index + 1) + width: parent.width + Rectangle { + text: "bla" + } + MyComponent { + text: root.text + function f(v = 4){ + let c = 0 + return { + a: function(){ if (b == 0) c += 78*5*v; }() + } + } + property int a: { + return 45 + } + } + } + } + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/file1Reformatted.qml b/tests/auto/qmldom/domdata/reformatter/file1Reformatted.qml new file mode 100644 index 0000000000..244a10f3f6 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/file1Reformatted.qml @@ -0,0 +1,49 @@ +pragma pippo +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { + height: 480 + title: qsTr("Scroll") + visible: true + width: 640 + + Rectangle { + anchors.fill: parent + + ListView { + model: { + MySingleton.mySignal(); + 20; + } + width: parent.width + + delegate: ItemDelegate { + id: root + text: "Item " + (index + 1) + width: parent.width + + Rectangle { + text: "bla" + } + MyComponent { + property int a: { + return 45; + } + + text: root.text + + function f(v = 4) { + let c = 0; + return { + "a": function () { + if (b == 0) + c += 78 * 5 * v; + }() + }; + } + } + } + } + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/file1Unindented.qml b/tests/auto/qmldom/domdata/reformatter/file1Unindented.qml new file mode 100644 index 0000000000..146bafee00 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/file1Unindented.qml @@ -0,0 +1,42 @@ +pragma pippo +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { +visible: true +width: 640 +height: 480 +title: qsTr("Scroll") + +Rectangle { +anchors.fill: parent + +ListView { +width: parent.width +model: { +MySingleton.mySignal() +20 +} +delegate: ItemDelegate { +id: root +text: "Item " + (index + 1) +width: parent.width +Rectangle { +text: "bla" +} +MyComponent { +text: root.text +function f(v = 4){ +let c = 0 +return { +a: function(){ if (b == 0) c += 78*5*v; }() +} +} +property int a: { +return 45 +} +} +} +} +} +} diff --git a/tests/auto/qmldom/domdata/reformatter/file2.qml b/tests/auto/qmldom/domdata/reformatter/file2.qml new file mode 100644 index 0000000000..5aeebc14e6 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/file2.qml @@ -0,0 +1,58 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { + visible: true + width: 640 + height: 480 + title: qsTr("Scroll") + + onTrigger: console.log("trigger signal emitted") + + onSend: { + console.log("send signal emitted with notice: " + notice) + } + + Rectangle { + anchors.fill: parent + + ListView { + width: parent.width + model: { + MySingleton.mySignal() + 20 + } + delegate: ItemDelegate { + id: root + text: "Item " + (index + 1) + width: parent.width + Rectangle { + text: "bla" + } + MyComponent { + text: root.text + function f(v){ + let c = 0 + return { + a: function(){ if (b == 0) c += 78*5*v; }() + } + } + property int a: { + let x = isNaN; + (45) + x ? 5 + 1 : 8 + } + property list<Item> b: [ Item{ + width: 5 + }, + Item{ + width: 6 + }] + } + } + } + } + Component.onCompleted: { + console.log("loaded") + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/file2Reformatted.qml b/tests/auto/qmldom/domdata/reformatter/file2Reformatted.qml new file mode 100644 index 0000000000..30ad8f0618 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/file2Reformatted.qml @@ -0,0 +1,66 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { + height: 480 + title: qsTr("Scroll") + visible: true + width: 640 + + Component.onCompleted: { + console.log("loaded"); + } + onSend: { + console.log("send signal emitted with notice: " + notice); + } + onTrigger: console.log("trigger signal emitted") + + Rectangle { + anchors.fill: parent + + ListView { + model: { + MySingleton.mySignal(); + 20; + } + width: parent.width + + delegate: ItemDelegate { + id: root + text: "Item " + (index + 1) + width: parent.width + + Rectangle { + text: "bla" + } + MyComponent { + property int a: { + let x = isNaN; + (45); + x ? 5 + 1 : 8; + } + property list<Item> b: [ + Item { + width: 5 + }, + Item { + width: 6 + } + ] + + text: root.text + + function f(v) { + let c = 0; + return { + "a": function () { + if (b == 0) + c += 78 * 5 * v; + }() + }; + } + } + } + } + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/inline.qml b/tests/auto/qmldom/domdata/reformatter/inline.qml new file mode 100644 index 0000000000..3429e9a2af --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/inline.qml @@ -0,0 +1,8 @@ +import QtQuick + +Item { +component CustomText: Text { +color: "red" +text: "Test Text" +} +} diff --git a/tests/auto/qmldom/domdata/reformatter/inlineReformatted.qml b/tests/auto/qmldom/domdata/reformatter/inlineReformatted.qml new file mode 100644 index 0000000000..749da25332 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/inlineReformatted.qml @@ -0,0 +1,8 @@ +import QtQuick + +Item { + component CustomText: Text { + color: "red" + text: "Test Text" + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/required.qml b/tests/auto/qmldom/domdata/reformatter/required.qml new file mode 100644 index 0000000000..29103114bd --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/required.qml @@ -0,0 +1,13 @@ +import QtQuick 2.15 + +Item { + id: theFoo + + required property Item theItem + required data + + function foo() { + theItem.foo("The issue is exacerbated if the object literal is wrapped onto the next line like so:", + {"foo": theFoo}) + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/requiredReformatted.qml b/tests/auto/qmldom/domdata/reformatter/requiredReformatted.qml new file mode 100644 index 0000000000..8d199d9ad7 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/requiredReformatted.qml @@ -0,0 +1,13 @@ +import QtQuick 2.15 + +Item { + id: theFoo + required data + required property Item theItem + + function foo() { + theItem.foo("The issue is exacerbated if the object literal is wrapped onto the next line like so:", { + "foo": theFoo + }); + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/requiredReformatted2.qml b/tests/auto/qmldom/domdata/reformatter/requiredReformatted2.qml new file mode 100644 index 0000000000..44685765da --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/requiredReformatted2.qml @@ -0,0 +1,13 @@ +import QtQuick 2.15 + +Item { + id: theFoo + required data + required property Item theItem + + function foo() { + theItem.foo("The issue is exacerbated if the object literal is wrapped onto the next line like so:", { + "foo": theFoo + }); + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/spread.qml b/tests/auto/qmldom/domdata/reformatter/spread.qml new file mode 100644 index 0000000000..04fba62f9d --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/spread.qml @@ -0,0 +1,14 @@ +import QtQuick 2.15 + +Item { + function myFunction() {} + function foo() { + iterableObj = [1,2] + obj = {a:42} + myFunction(...iterableObj); // pass all elements of iterableObj as arguments to function myFunction + let arr = [...iterableObj, '4', 'five', 6]; // combine two arrays by inserting all elements from iterableObj + //let objClone = { ...obj }; // pass all key:value pairs from an object (ES2018) + myFunction(-1, ...args, 2, ...[3]); + console.log(Math.max(...[1, 2, 3, 4])) + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/spreadReformatted.qml b/tests/auto/qmldom/domdata/reformatter/spreadReformatted.qml new file mode 100644 index 0000000000..795a28257a --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/spreadReformatted.qml @@ -0,0 +1,17 @@ +import QtQuick 2.15 + +Item { + function foo() { + iterableObj = [1, 2]; + obj = { + "a": 42 + }; + myFunction(...iterableObj); // pass all elements of iterableObj as arguments to function myFunction + let arr = [...iterableObj, '4', 'five', 6]; // combine two arrays by inserting all elements from iterableObj + //let objClone = { ...obj }; // pass all key:value pairs from an object (ES2018) + myFunction(-1, ...args, 2, ...[3]); + console.log(Math.max(...[1, 2, 3, 4])); + } + function myFunction() { + } +} diff --git a/tests/auto/qmldom/domdata/reformatter/template.qml b/tests/auto/qmldom/domdata/reformatter/template.qml new file mode 100644 index 0000000000..886922838b --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/template.qml @@ -0,0 +1,22 @@ +import QtQuick 2.15 + +Text { + property int i: 3 + text: "´"+ + "m + l + + "+ + 'b'+' + multi + l + l'+ + `template` + + `t${i+6}`+ + `t${i+`nested${i}`}`+ + `t${function(){return 5}()}`+ + `t\${i} + ${i + + 2}` + width: 300 +} diff --git a/tests/auto/qmldom/domdata/reformatter/templateReformatted.qml b/tests/auto/qmldom/domdata/reformatter/templateReformatted.qml new file mode 100644 index 0000000000..bfc8d28db1 --- /dev/null +++ b/tests/auto/qmldom/domdata/reformatter/templateReformatted.qml @@ -0,0 +1,17 @@ +import QtQuick 2.15 + +Text { + property int i: 3 + + text: "´" + "m + l + + " + 'b' + ' + multi + l + l' + `template` + `t${i + 6}` + `t${i + `nested${i}`}` + `t${function () { + return 5; + }()}` + `t\${i} + ${i + 2}` + width: 300 +} diff --git a/tests/auto/qmldom/reformatter/CMakeLists.txt b/tests/auto/qmldom/reformatter/CMakeLists.txt new file mode 100644 index 0000000000..4e6f1d1a06 --- /dev/null +++ b/tests/auto/qmldom/reformatter/CMakeLists.txt @@ -0,0 +1,27 @@ +##################################################################### +## tst_reformatter: +##################################################################### +# Collect test data +file(GLOB_RECURSE test_data_glob + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/.. + domdata/reformatter/*) +list(APPEND test_data ${test_data_glob}) + +qt_internal_add_test(tst_reformatter + SOURCES + tst_reformatter.cpp tst_reformatter.h + DEFINES + QT_DEPRECATED_WARNINGS + QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../domdata\\\" + PUBLIC_LIBRARIES + Qt::Core + Qt::QmlDevToolsPrivate + Qt::QmlDomPrivate + Qt::Test + TESTDATA ${test_data} +) + +qt_internal_extend_target(tst_reformatter CONDITION ANDROID OR IOS + DEFINES + QT_REFORMATTERTEST_DATADIR=\\\":/domdata\\\" +) diff --git a/tests/auto/qmldom/reformatter/tst_reformatter.cpp b/tests/auto/qmldom/reformatter/tst_reformatter.cpp new file mode 100644 index 0000000000..848f6d525f --- /dev/null +++ b/tests/auto/qmldom/reformatter/tst_reformatter.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +**/ +#include "tst_reformatter.h" + +QTEST_MAIN(QQmlJS::Dom::TestReformatter) diff --git a/tests/auto/qmldom/reformatter/tst_reformatter.h b/tests/auto/qmldom/reformatter/tst_reformatter.h new file mode 100644 index 0000000000..26593fcfe2 --- /dev/null +++ b/tests/auto/qmldom/reformatter/tst_reformatter.h @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +**/ +#ifndef TST_QMLDOMCODEFORMATTER_H +#define TST_QMLDOMCODEFORMATTER_H +#include <QtQmlDom/private/qqmldomlinewriter_p.h> +#include <QtQmlDom/private/qqmldomoutwriter_p.h> +#include <QtQmlDom/private/qqmldomitem_p.h> +#include <QtQmlDom/private/qqmldomtop_p.h> + +#include <QtTest/QtTest> +#include <QCborValue> +#include <QDebug> +#include <QLibraryInfo> + +#include <memory> + +QT_BEGIN_NAMESPACE +namespace QQmlJS { +namespace Dom { + +class TestReformatter : public QObject +{ + Q_OBJECT +public: +private slots: + + void manualReformatter_data() + { + LineWriterOptions noReorderOptions; + QTest::addColumn<QString>("inFile"); + QTest::addColumn<QString>("outFile"); + QTest::addColumn<LineWriterOptions>("options"); + LineWriterOptions defaultOptions; + + noReorderOptions.attributesSequence = LineWriterOptions::AttributesSequence::Preserve; + + QTest::newRow("file1") << QStringLiteral(u"file1.qml") + << QStringLiteral(u"file1Reformatted.qml") << defaultOptions; + + QTest::newRow("file2") << QStringLiteral(u"file2.qml") + << QStringLiteral(u"file2Reformatted.qml") << defaultOptions; + + QTest::newRow("commentedFile") + << QStringLiteral(u"commentedFile.qml") + << QStringLiteral(u"commentedFileReformatted2.qml") << defaultOptions; + + QTest::newRow("required") << QStringLiteral(u"required.qml") + << QStringLiteral(u"requiredReformatted2.qml") << defaultOptions; + + QTest::newRow("inline") << QStringLiteral(u"inline.qml") + << QStringLiteral(u"inlineReformatted.qml") << defaultOptions; + + QTest::newRow("spread") << QStringLiteral(u"spread.qml") + << QStringLiteral(u"spreadReformatted.qml") << defaultOptions; + + QTest::newRow("template") << QStringLiteral(u"template.qml") + << QStringLiteral(u"templateReformatted.qml") << defaultOptions; + + QTest::newRow("file1NoReorder") + << QStringLiteral(u"file1.qml") << QStringLiteral(u"file1Reformatted2.qml") + << noReorderOptions; + } + + void manualReformatter() + { + QFETCH(QString, inFile); + QFETCH(QString, outFile); + QFETCH(LineWriterOptions, options); + + QString baseDir = QLatin1String(QT_QMLTEST_DATADIR) + QLatin1String("/reformatter"); + QStringList qmltypeDirs = + QStringList({ baseDir, QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath) }); + DomItem env = DomEnvironment::create( + qmltypeDirs, + QQmlJS::Dom::DomEnvironment::Option::SingleThreaded + | QQmlJS::Dom::DomEnvironment::Option::NoDependencies); + QString testFilePath = baseDir + QLatin1Char('/') + inFile; + DomItem tFile; + env.loadBuiltins(); + env.loadFile( + testFilePath, QString(), + [&tFile](Path, const DomItem &, const DomItem &newIt) { tFile = newIt; }, + LoadOption::DefaultLoad); + env.loadPendingDependencies(); + + MutableDomItem myFile = tFile.field(Fields::currentItem); + + QString resultStr; + QTextStream res(&resultStr); + LineWriter lw([&res](QStringView s) { res << s; }, QLatin1String("*testStream*"), options); + OutWriter ow(lw); + ow.indentNextlines = true; + DomItem qmlFile = tFile.field(Fields::currentItem); + qmlFile.writeOut(ow); + lw.eof(); + res.flush(); + QString fullRes = resultStr; + res.seek(0); + QFile fOut(baseDir + QLatin1Char('/') + outFile); + if (!fOut.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "could not open file" << outFile; + return; + } + QTextStream out(&fOut); + QString line = out.readLine(); + QString resLine = res.readLine(); + int iLine = 0; + auto writeReformatted = [fullRes]() { + qDebug().noquote().nospace() << "Reformatted output:\n" + << "-----------------\n" + << fullRes << "-----------------\n"; + }; + while (!line.isNull() && !resLine.isNull()) { + ++iLine; + if (resLine != line) + writeReformatted(); + QCOMPARE(resLine, line); + line = out.readLine(); + resLine = res.readLine(); + } + if (resLine.isNull() != line.isNull()) { + writeReformatted(); + qDebug() << "reformatted at end" << resLine.isNull() << resLine + << "reference at end:" << line.isNull() << line; + } + QCOMPARE(resLine.isNull(), line.isNull()); + } + + void indentInfo() + { + IndentInfo i1(u"\n\n ", 4); + QCOMPARE(i1.trailingString, u" "); + QCOMPARE(i1.nNewlines, 2); + QCOMPARE(i1.column, 2); + IndentInfo i2(u"\r\n\r\n ", 4); + QCOMPARE(i2.trailingString, u" "); + QCOMPARE(i2.nNewlines, 2); + QCOMPARE(i2.column, 2); + IndentInfo i3(u"\n ", 4); + QCOMPARE(i3.trailingString, u" "); + QCOMPARE(i3.nNewlines, 1); + QCOMPARE(i3.column, 1); + IndentInfo i4(u"\r\n ", 4); + QCOMPARE(i4.trailingString, u" "); + QCOMPARE(i4.nNewlines, 1); + QCOMPARE(i4.column, 1); + IndentInfo i5(u"\n", 4); + QCOMPARE(i5.trailingString, u""); + QCOMPARE(i5.nNewlines, 1); + QCOMPARE(i5.column, 0); + IndentInfo i6(u"\r\n", 4); + QCOMPARE(i6.trailingString, u""); + QCOMPARE(i6.nNewlines, 1); + QCOMPARE(i6.column, 0); + IndentInfo i7(u" ", 4); + QCOMPARE(i7.trailingString, u" "); + QCOMPARE(i7.nNewlines, 0); + QCOMPARE(i7.column, 2); + IndentInfo i8(u"", 4); + QCOMPARE(i8.trailingString, u""); + QCOMPARE(i8.nNewlines, 0); + QCOMPARE(i8.column, 0); + } + + void lineWriter() + { + { + QString res; + LineWriterOptions opts; + opts.lineEndings = LineWriterOptions::LineEndings::Unix; + LineWriter lw([&res](QStringView v) { res.append(v); }, QLatin1String("*testStream*"), + opts); + lw.write(u"a\nb"); + lw.write(u"c\r\nd"); + lw.write(u"e\rf"); + lw.write(u"g\r\n"); + lw.write(u"h\r"); + lw.write(u"\n"); + QCOMPARE(res, u"a\nbc\nde\nfg\nh\n\n"); + } + { + QString res; + LineWriterOptions opts; + opts.lineEndings = LineWriterOptions::LineEndings::Windows; + LineWriter lw([&res](QStringView v) { res.append(v); }, QLatin1String("*testStream*"), + opts); + lw.write(u"a\nb"); + lw.write(u"c\r\nd"); + lw.write(u"e\rf"); + lw.write(u"g\r\n"); + lw.write(u"h\r"); + lw.write(u"\n"); + QCOMPARE(res, u"a\r\nbc\r\nde\r\nfg\r\nh\r\n\r\n"); + } + { + QString res; + LineWriterOptions opts; + opts.lineEndings = LineWriterOptions::LineEndings::OldMacOs; + LineWriter lw([&res](QStringView v) { res.append(v); }, QLatin1String("*testStream*"), + opts); + lw.write(u"a\nb"); + lw.write(u"c\r\nd"); + lw.write(u"e\rf"); + lw.write(u"g\r\n"); + lw.write(u"h\r"); + lw.write(u"\n"); + QCOMPARE(res, u"a\rbc\rde\rfg\rh\r\r"); + } + } + +private: +}; + +} // namespace Dom +} // namespace QQmlJS +QT_END_NAMESPACE + +#endif // TST_QMLDOMSCANNER_H |