diff options
Diffstat (limited to 'tests/auto/qml/qmlformat')
-rw-r--r-- | tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml | 106 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/Annotations.formatted.qml | 106 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/Annotations.qml | 76 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml | 152 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/Example1.formatted.qml | 152 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/Example1.qml | 105 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/FrontInline.formatted.qml | 3 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/FrontInline.qml | 2 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml | 63 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/IfBlocks.qml | 66 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml | 29 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/data/readOnlyProps.qml | 15 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/qmlformat.pro | 12 | ||||
-rw-r--r-- | tests/auto/qml/qmlformat/tst_qmlformat.cpp | 300 |
14 files changed, 1187 insertions, 0 deletions
diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml new file mode 100644 index 0000000000..a05c2125dc --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![2] +import QtQuick 2.0 +//![2] +import QtCharts 2.0 + +@Pippo { + atg1: 3 +} +@Annotation2 { +} +Item { + //![1] + + @AnnotateMore { + property int x: 5 + } + @AnnotateALot { + } + + property variant othersSlice: 0 + @Annotate { + } + + anchors.fill: parent + @SuperComplete { + binding: late + } + Component.onCompleted: { + // You can also manipulate slices dynamically, like append a slice or set a slice exploded + othersSlice = pieSeries.append("Others", 52); + pieSeries.find("Volkswagen").exploded = true; + } + //![1] + ChartView { + id: chart + + title: "Top-5 car brand shares in Finland" + anchors.fill: parent + legend.alignment: Qt.AlignBottom + antialiasing: true + + @ExtraAnnotation { + signal pippo() + } + PieSeries { + id: pieSeries + + PieSlice { + label: "Volkswagen" + value: 13.5 + } + + PieSlice { + label: "Toyota" + value: 10.9 + } + + PieSlice { + label: "Ford" + value: 8.6 + } + + PieSlice { + label: "Skoda" + value: 8.2 + } + + PieSlice { + label: "Volvo" + value: 6.8 + } + + } + + } + +} diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml new file mode 100644 index 0000000000..a142d4cb74 --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![2] +import QtCharts 2.0 +//![2] +import QtQuick 2.0 + +@Pippo { + atg1: 3 +} +@Annotation2 { +} +Item { + //![1] + + @AnnotateMore { + property int x: 5 + } + @AnnotateALot { + } + + property variant othersSlice: 0 + @Annotate { + } + + anchors.fill: parent + @SuperComplete { + binding: late + } + Component.onCompleted: { + // You can also manipulate slices dynamically, like append a slice or set a slice exploded + othersSlice = pieSeries.append("Others", 52); + pieSeries.find("Volkswagen").exploded = true; + } + //![1] + ChartView { + id: chart + + title: "Top-5 car brand shares in Finland" + anchors.fill: parent + legend.alignment: Qt.AlignBottom + antialiasing: true + + @ExtraAnnotation { + signal pippo() + } + PieSeries { + id: pieSeries + + PieSlice { + label: "Volkswagen" + value: 13.5 + } + + PieSlice { + label: "Toyota" + value: 10.9 + } + + PieSlice { + label: "Ford" + value: 8.6 + } + + PieSlice { + label: "Skoda" + value: 8.2 + } + + PieSlice { + label: "Volvo" + value: 6.8 + } + + } + + } + +} diff --git a/tests/auto/qml/qmlformat/data/Annotations.qml b/tests/auto/qml/qmlformat/data/Annotations.qml new file mode 100644 index 0000000000..2d3d7d2cfd --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Annotations.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![2] +import QtQuick 2.0 +//![2] +import QtCharts 2.0 + +@Pippo{ atg1:3 } +@Annotation2{} +Item { + @Annotate{} + anchors.fill: parent + @AnnotateMore{ + property int x: 5 + } + @AnnotateALot{} + property variant othersSlice: 0 + + //![1] + ChartView { + id: chart + title: "Top-5 car brand shares in Finland" + anchors.fill: parent + legend.alignment: Qt.AlignBottom + antialiasing: true + +@ExtraAnnotation{ + signal pippo +} + PieSeries { + id: pieSeries + PieSlice { label: "Volkswagen"; value: 13.5 } + PieSlice { label: "Toyota"; value: 10.9 } + PieSlice { label: "Ford"; value: 8.6 } + PieSlice { label: "Skoda"; value: 8.2 } + PieSlice { label: "Volvo"; value: 6.8 } + } + } + +@SuperComplete{ +binding: late +} + Component.onCompleted: { + // You can also manipulate slices dynamically, like append a slice or set a slice exploded + othersSlice = pieSeries.append("Others", 52.0); + pieSeries.find("Volkswagen").exploded = true; + } + //![1] +} diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml new file mode 100644 index 0000000000..34d58cf571 --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml @@ -0,0 +1,152 @@ +/* This file is licensed under the not a license license + 1. You may not comply + 2. Goodbye +*/ + +// Importing this is very important +import QtQuick 5.15 +// Muddling the waters! +import QtQuick.Models 3.14 as muddle +// Importing that is important too +import Z +import That +import This // THIS IS VERY IMPORTANT! +import Y +import X.Z +import X.Y +import A.LLOHA +import A.B.B.A + +// This comment is related to Item +Item { + // Orphan comment + // Another orphan + // More orphans + + // This to id + // Also id. (line 2) + // This is the third id + // fourth id comment + id: foo + + // This to enum + enum Foo { + A = 3, // This is A + B, // This is B + C = 4, // This is C + D // This is D + } + + property bool some_bool: false + property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3] + property bool something_computed: function(x) { + // This is an orphan inside something_computed + // Are these getting duplicated? + // Another orphan inside something_computed + + const PI = 3, DAYS_PER_YEAR = 365.25; + var x = 3 + 2; + x["bla"] = 50; + // This one to var few! + var few = new WhatEver(); + x += Math.sin(3); + x--; + --x; + x++; + ++x; + for (var x = 0; x < 100; x++) { + x++; + console.log("Foo"); + } + for (var x in [3, 2, 1]) { + y++; + console.log("Bar"); + } + while (true) + console.log("Wee"); + + with (foo) { + bar; + x += 5; + } // This is related to with! + x3: + do { + console.log("Hello"); + } while (3 == 0); + try { + dangerous(); + } catch (e) { + console.log(e); + } finally { + dangerous(); + } + switch (x) { + case 0: + x = 1; + break; + case 1: + x = 5; + break; + case 4: + x = 100; + break; + } + if (x == 50) + console.log("true"); + else if (x == 50) + console.log("other thing"); + else + console.log("false"); + + if (x == 50) { + console.log("true"); + } else if (x == 50) { + console.log("other thing"); + x--; + } else { + console.log("false"); + } + return "foobar"; + }() + default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool + // some_read_only_bool + readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0 + + signal say(string name, bool caps) + + // This one to aFunc() + function aFunc() { + var x = 3; + return x; + } + + x: 3 // Very cool + Component.onCompleted: console.log("Foo!") + myFavouriteThings: [ + // This is an orphan + + // This is a cool text + Text { + }, + // This is a cool rectangle + Rectangle { + } + ] + + Text { + required property string batman + + signal boo(int count, int times, real duration) + + text: "Bla" + } + + // This comment is related to the property animation + PropertyAnimation on x { + id: foo + + x: 3 + y: x + 3 + } + +} diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.qml new file mode 100644 index 0000000000..b06734eb0b --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Example1.formatted.qml @@ -0,0 +1,152 @@ +/* This file is licensed under the not a license license + 1. You may not comply + 2. Goodbye +*/ + +import A.B.B.A +import A.LLOHA +// Importing this is very important +import QtQuick 5.15 +// Muddling the waters! +import QtQuick.Models 3.14 as muddle +import That +import This // THIS IS VERY IMPORTANT! +import X.Y +import X.Z +import Y +// Importing that is important too +import Z + +// This comment is related to Item +Item { + // Orphan comment + // Another orphan + // More orphans + + // This to id + // Also id. (line 2) + // This is the third id + // fourth id comment + id: foo + + // This to enum + enum Foo { + A = 3, // This is A + B, // This is B + C = 4, // This is C + D // This is D + } + + property bool some_bool: false + property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3] + property bool something_computed: function(x) { + // This is an orphan inside something_computed + // Are these getting duplicated? + // Another orphan inside something_computed + + const PI = 3, DAYS_PER_YEAR = 365.25; + var x = 3 + 2; + x["bla"] = 50; + // This one to var few! + var few = new WhatEver(); + x += Math.sin(3); + x--; + --x; + x++; + ++x; + for (var x = 0; x < 100; x++) { + x++; + console.log("Foo"); + } + for (var x in [3, 2, 1]) { + y++; + console.log("Bar"); + } + while (true) + console.log("Wee"); + + with (foo) { + bar; + x += 5; + } // This is related to with! + x3: + do { + console.log("Hello"); + } while (3 == 0); + try { + dangerous(); + } catch (e) { + console.log(e); + } finally { + dangerous(); + } + switch (x) { + case 0: + x = 1; + break; + case 1: + x = 5; + break; + case 4: + x = 100; + break; + } + if (x == 50) + console.log("true"); + else if (x == 50) + console.log("other thing"); + else + console.log("false"); + + if (x == 50) { + console.log("true"); + } else if (x == 50) { + console.log("other thing"); + x--; + } else { + console.log("false"); + } + return "foobar"; + }() + default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool + // some_read_only_bool + readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0 + + signal say(string name, bool caps) + + // This one to aFunc() + function aFunc() { + var x = 3; + return x; + } + + x: 3 // Very cool + Component.onCompleted: console.log("Foo!") + myFavouriteThings: [ + // This is an orphan + + // This is a cool text + Text { + }, + // This is a cool rectangle + Rectangle { + } + ] + + Text { + required property string batman + + signal boo(int count, int times, real duration) + + text: "Bla" + } + + // This comment is related to the property animation + PropertyAnimation on x { + id: foo + + x: 3 + y: x + 3 + } + +} diff --git a/tests/auto/qml/qmlformat/data/Example1.qml b/tests/auto/qml/qmlformat/data/Example1.qml new file mode 100644 index 0000000000..0fb9053e3a --- /dev/null +++ b/tests/auto/qml/qmlformat/data/Example1.qml @@ -0,0 +1,105 @@ + + +/* This file is licensed under the not a license license + 1. You may not comply + 2. Goodbye +*/ + +// Importing this is very important +import QtQuick 5.15 +// Muddling the waters! +import QtQuick.Models 3.14 as muddle +// Importing that is important too +import Z +import That +import This // THIS IS VERY IMPORTANT! +import Y +import X.Z +import X.Y +import A.LLOHA +import A.B.B.A + +// This comment is related to Item +Item { + x: 3 // Very cool + + // This to enum + enum Foo { + A = 3, // This is A + B, // This is B + C = 4, // This is C + D // This is D + } + + // This one to aFunc() + function aFunc() { + var x = 3; + return x; + } + + property bool some_bool : false + // This comment is related to the property animation + PropertyAnimation on x { + id: foo; x: 3; y: x + 3 + } + + // Orphan comment + + // Another orphan + + // More orphans + + + property variant some_array_literal: [30,20,Math["PI"],[4,3,2],"foo",0.3] + property bool something_computed: function(x) { + const PI = 3, DAYS_PER_YEAR=365.25; var x = 3 + 2; x["bla"] = 50; + + // This is an orphan inside something_computed + + // Are these getting duplicated? + + + // This one to var few! + var few = new WhatEver(); + x += Math.sin(3); x--; --x; x++; ++x; + for (var x = 0; x < 100; x++) { x++; console.log("Foo"); } + for (var x in [3,2,1]) { y++; console.log("Bar"); } + while (true) { console.log("Wee"); } + with (foo) { bar; x+=5; } // This is related to with! + x3: + do { console.log("Hello"); } while (3 == 0) + try { dangerous(); } catch(e) { console.log(e); } finally { console.log("What else?"); } + switch (x) { case 0: x = 1; break; case 1: x = 5; break; case 4: x = 100; break; } + if (x == 50) { console.log("true"); } else if (x == 50) { console.log("other thing"); } else { console.log("false"); } + if (x == 50) { console.log("true"); } else if (x == 50) { console.log("other thing"); x--; } else { console.log("false"); } + + // Another orphan inside something_computed + + return "foobar"; }(); + + default property bool some_default_bool : 500 % 5 !== 0 // some_default_bool + + myFavouriteThings: [ + // This is an orphan + + // This is a cool text + Text {}, + // This is a cool rectangle + Rectangle {}] + + // some_read_only_bool + readonly property bool some_read_only_bool : Math.sin(3) && (aFunc()[30] + 5) | 2 != 0 + + signal say(string name, bool caps); + + Text { text: "Bla"; signal boo(int count, int times, real duration); required property string batman; } + + Component.onCompleted: console.log("Foo!"); + + // This to id + // Also id. (line 2) + // This is the third id + // fourth id comment + id: foo + +} diff --git a/tests/auto/qml/qmlformat/data/FrontInline.formatted.qml b/tests/auto/qml/qmlformat/data/FrontInline.formatted.qml new file mode 100644 index 0000000000..620fbf4120 --- /dev/null +++ b/tests/auto/qml/qmlformat/data/FrontInline.formatted.qml @@ -0,0 +1,3 @@ +// This comment should be directly above Item after formatting +Item { +} diff --git a/tests/auto/qml/qmlformat/data/FrontInline.qml b/tests/auto/qml/qmlformat/data/FrontInline.qml new file mode 100644 index 0000000000..c63265481c --- /dev/null +++ b/tests/auto/qml/qmlformat/data/FrontInline.qml @@ -0,0 +1,2 @@ +Item { // This comment should be directly above Item after formatting +} diff --git a/tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml b/tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml new file mode 100644 index 0000000000..b8e77ec23a --- /dev/null +++ b/tests/auto/qml/qmlformat/data/IfBlocks.formatted.qml @@ -0,0 +1,63 @@ +Item { + + function test() { + //// The following if blocks should NOT HAVE braces + // Single branch, no braces + if (true) + console.log("foo"); + + // Single branch, no braces + if (true) + console.log("foo"); + + // Multiple branches, No braces + if (true) + console.log("foo"); + else if (false) + console.log("bar"); + else + console.log("baz"); + // Multiple branches, all braces + if (true) + console.log("foo"); + else if (false) + console.log("bar"); + else + console.log("baz"); + + //// The following if blocks should HAVE braces + // Single branch, braces + if (true) { + console.log("foo"); + console.log("bar"); + } + // Multiple branches, some braces + if (true) { + console.log("foo"); + console.log("foo2"); + } else if (false) { + console.log("bar"); + } else { + console.log("baz"); + } + // Multiple branches, some braces + if (true) { + console.log("foo"); + } else if (false) { + console.log("bar"); + console.log("bar2"); + } else { + console.log("baz"); + } + // Multiple branches, some braces + if (true) { + console.log("foo"); + } else if (false) { + console.log("bar"); + } else { + console.log("baz"); + console.log("baz2"); + } + } + +} diff --git a/tests/auto/qml/qmlformat/data/IfBlocks.qml b/tests/auto/qml/qmlformat/data/IfBlocks.qml new file mode 100644 index 0000000000..505988b238 --- /dev/null +++ b/tests/auto/qml/qmlformat/data/IfBlocks.qml @@ -0,0 +1,66 @@ +Item { + function test() { + //// The following if blocks should NOT HAVE braces + // Single branch, no braces + if (true) + console.log("foo"); + + // Single branch, no braces + if (true) { + console.log("foo"); + } + + + // Multiple branches, No braces + if (true) + console.log("foo"); + else if (false) + console.log("bar"); + else + console.log("baz"); + + // Multiple branches, all braces + if (true) { + console.log("foo"); + } else if (false) { + console.log("bar"); + } else { + console.log("baz"); + } + + //// The following if blocks should HAVE braces + // Single branch, braces + if (true) { + console.log("foo"); + console.log("bar"); + } + + // Multiple branches, some braces + if (true) { + console.log("foo"); + console.log("foo2"); + } else if (false) + console.log("bar"); + else + console.log("baz"); + + // Multiple branches, some braces + if (true) + console.log("foo"); + else if (false) { + console.log("bar"); + console.log("bar2"); + } else + console.log("baz"); + + // Multiple branches, some braces + if (true) + console.log("foo"); + else if (false) + console.log("bar"); + else { + console.log("baz"); + console.log("baz2"); + } + } +} diff --git a/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml b/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml new file mode 100644 index 0000000000..6e7cc31dcf --- /dev/null +++ b/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml @@ -0,0 +1,29 @@ +import QtQuick 2.0 + +QtObject { + // Testing UiObjectBinding + readonly property Item + item: Item { + id: test + + signal foo() + } + // End comment + + // Testing UiArrayBinding + readonly property list<Item> array: [ + Item { + id: test1 + + signal foo() + }, + Item { + id: test2 + + signal bar() + } + ] + // Testing UiScriptBinding + readonly property int script: Math.sin(Math.PI) + property bool normalProperty: true +} diff --git a/tests/auto/qml/qmlformat/data/readOnlyProps.qml b/tests/auto/qml/qmlformat/data/readOnlyProps.qml new file mode 100644 index 0000000000..8a32dd131e --- /dev/null +++ b/tests/auto/qml/qmlformat/data/readOnlyProps.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +QtObject { + // Testing UiObjectBinding + readonly property Item item: Item { id: test; signal foo() } + // End comment + + // Testing UiArrayBinding + readonly property list<Item> array: [ Item { id: test1; signal foo() }, Item { id: test2; signal bar() } ] + + // Testing UiScriptBinding + readonly property int script: Math.sin(Math.PI) + + property bool normalProperty: true +} diff --git a/tests/auto/qml/qmlformat/qmlformat.pro b/tests/auto/qml/qmlformat/qmlformat.pro new file mode 100644 index 0000000000..a6ae391711 --- /dev/null +++ b/tests/auto/qml/qmlformat/qmlformat.pro @@ -0,0 +1,12 @@ +CONFIG += testcase +TARGET = tst_qmlformat +macos:CONFIG -= app_bundle + +SOURCES += tst_qmlformat.cpp +DEFINES += SRCDIR=\\\"$$PWD\\\" + +include (../../shared/util.pri) + +TESTDATA = data/* + +QT += testlib diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp new file mode 100644 index 0000000000..5a8974b907 --- /dev/null +++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QDir> +#include <QFile> +#include <QProcess> +#include <QString> +#include <QTemporaryDir> + +#include <util.h> + +class TestQmlformat: public QQmlDataTest +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() override; + + void testFormat(); + void testFormatNoSort(); + void testAnnotations(); + void testAnnotationsNoSort(); + void testLineEndings(); + void testFrontInline(); + void testIfBlocks(); + + void testReadOnlyProps(); + +#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled + void testExample(); + void testExample_data(); +#endif + +private: + QString readTestFile(const QString &path); + QString runQmlformat(const QString &fileToFormat, bool sortImports, bool shouldSucceed, const QString &newlineFormat = "native"); + + QString m_qmlformatPath; + QStringList m_excludedDirs; + QStringList m_invalidFiles; + + QStringList findFiles(const QDir &); + bool isInvalidFile(const QFileInfo &fileName) const; +}; + +void TestQmlformat::initTestCase() +{ + QQmlDataTest::initTestCase(); + m_qmlformatPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmlformat"); +#ifdef Q_OS_WIN + m_qmlformatPath += QLatin1String(".exe"); +#endif + if (!QFileInfo(m_qmlformatPath).exists()) { + QString message = QStringLiteral("qmlformat executable not found (looked for %0)").arg(m_qmlformatPath); + QFAIL(qPrintable(message)); + } + + // Add directories you want excluded here + + // These snippets are not expected to run on their own. + m_excludedDirs << "doc/src/snippets/qml/visualdatamodel_rootindex"; + m_excludedDirs << "doc/src/snippets/qml/qtbinding"; + m_excludedDirs << "doc/src/snippets/qml/imports"; + m_excludedDirs << "doc/src/snippets/qtquick1/visualdatamodel_rootindex"; + m_excludedDirs << "doc/src/snippets/qtquick1/qtbinding"; + m_excludedDirs << "doc/src/snippets/qtquick1/imports"; + m_excludedDirs << "tests/manual/v4"; + m_excludedDirs << "tests/auto/qml/ecmascripttests"; + m_excludedDirs << "tests/auto/qml/qmllint"; + + // Add invalid files (i.e. files with syntax errors) + m_invalidFiles << "tests/auto/quick/qquickloader/data/InvalidSourceComponent.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/signal.2.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/signal.3.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/signal.5.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/property.4.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/empty.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/missingObject.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/insertedSemicolon.1.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nonexistantProperty.5.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidRoot.1.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml"; + m_invalidFiles << "tests/auto/qml/qquickfolderlistmodel/data/dummy.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.1.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.2.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.3.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.4.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.5.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.6.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/numberParsing_error.1.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/numberParsing_error.2.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/incrDecrSemicolon_error1.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/incrDecrSemicolon_error1.qml"; + m_invalidFiles << "tests/auto/qml/debugger/qqmlpreview/data/broken.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.2.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.3.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.qml"; + m_invalidFiles << "tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml"; + m_invalidFiles << "tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml"; + + // These files rely on exact formatting + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/incrDecrSemicolon1.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/incrDecrSemicolon_error1.qml"; + m_invalidFiles << "tests/auto/qml/qqmlecmascript/data/incrDecrSemicolon2.qml"; +} + +QStringList TestQmlformat::findFiles(const QDir &d) +{ + for (int ii = 0; ii < m_excludedDirs.count(); ++ii) { + QString s = m_excludedDirs.at(ii); + if (d.absolutePath().endsWith(s)) + return QStringList(); + } + + QStringList rv; + + QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"), + QDir::Files); + foreach (const QString &file, files) { + rv << d.absoluteFilePath(file); + } + + QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot | + QDir::NoSymLinks); + foreach (const QString &dir, dirs) { + QDir sub = d; + sub.cd(dir); + rv << findFiles(sub); + } + + return rv; +} + +bool TestQmlformat::isInvalidFile(const QFileInfo &fileName) const +{ + for (const QString &invalidFile : m_invalidFiles) { + if (fileName.absoluteFilePath().endsWith(invalidFile)) + return true; + } + return false; +} + +QString TestQmlformat::readTestFile(const QString &path) +{ + QFile file(testFile(path)); + + if (!file.open(QIODevice::ReadOnly)) + return ""; + + return QString::fromUtf8(file.readAll()); +} + +void TestQmlformat::testFormat() +{ + QCOMPARE(runQmlformat(testFile("Example1.qml"), true, true), readTestFile("Example1.formatted.qml")); +} + +void TestQmlformat::testFormatNoSort() +{ + QCOMPARE(runQmlformat(testFile("Example1.qml"), false, true), readTestFile("Example1.formatted.nosort.qml")); +} + +void TestQmlformat::testAnnotations() +{ + QCOMPARE(runQmlformat(testFile("Annotations.qml"), true, true), readTestFile("Annotations.formatted.qml")); +} + +void TestQmlformat::testAnnotationsNoSort() +{ + QCOMPARE(runQmlformat(testFile("Annotations.qml"), false, true), readTestFile("Annotations.formatted.nosort.qml")); +} + +void TestQmlformat::testFrontInline() +{ + QCOMPARE(runQmlformat(testFile("FrontInline.qml"), false, true), readTestFile("FrontInline.formatted.qml")); +} + +void TestQmlformat::testIfBlocks() +{ + QCOMPARE(runQmlformat(testFile("IfBlocks.qml"), false, true), readTestFile("IfBlocks.formatted.qml")); +} + +void TestQmlformat::testReadOnlyProps() +{ + QCOMPARE(runQmlformat(testFile("readOnlyProps.qml"), false, true), readTestFile("readOnlyProps.formatted.qml")); +} + +void TestQmlformat::testLineEndings() +{ + // macos + const QString macosContents = runQmlformat(testFile("Example1.formatted.qml"), false, true, "macos"); + QVERIFY(!macosContents.contains("\n")); + QVERIFY(macosContents.contains("\r")); + + // windows + const QString windowsContents = runQmlformat(testFile("Example1.formatted.qml"), false, true, "windows"); + QVERIFY(windowsContents.contains("\r\n")); + + // unix + const QString unixContents = runQmlformat(testFile("Example1.formatted.qml"), false, true, "unix"); + QVERIFY(unixContents.contains("\n")); + QVERIFY(!unixContents.contains("\r")); +} + +#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled +void TestQmlformat::testExample_data() +{ + QTest::addColumn<QString>("file"); + + QString examples = QLatin1String(SRCDIR) + "/../../../../examples/"; + QString tests = QLatin1String(SRCDIR) + "/../../../../tests/"; + + QStringList files; + files << findFiles(QDir(examples)); + files << findFiles(QDir(tests)); + + for (const QString &file : files) + QTest::newRow(qPrintable(file)) << file; +} +#endif + +#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled +void TestQmlformat::testExample() +{ + QFETCH(QString, file); + QString output = runQmlformat(file, true, !isInvalidFile(file)); + + if (!isInvalidFile(file)) + QVERIFY(!output.isEmpty()); +} +#endif + +QString TestQmlformat::runQmlformat(const QString &fileToFormat, bool sortImports, bool shouldSucceed, const QString &newlineFormat) +{ + // Copy test file to temporary location + QTemporaryDir tempDir; + const QString tempFile = tempDir.path() + QDir::separator() + "to_format.qml"; + QFile::copy(fileToFormat, tempFile); + + QStringList args; + args << "-i"; + args << tempFile; + + if (!sortImports) + args << "-n"; + + args << "-l" << newlineFormat; + + auto verify = [&]() { + QProcess process; + process.start(m_qmlformatPath, args); + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + if (shouldSucceed) + QCOMPARE(process.exitCode(), 0); + }; + verify(); + + QFile temp(tempFile); + + temp.open(QIODevice::ReadOnly); + QString formatted = QString::fromUtf8(temp.readAll()); + + return formatted; +} + +QTEST_MAIN(TestQmlformat) +#include "tst_qmlformat.moc" |