qmlformat: improve testing of file based options

Add an option to run qmlformat from the original file to a copy, thus
picking up automatically settings related to those options.
This does not in place replacing, but does not need any special setup
to run the test.
Ensure that git preserves the old macos line endings (CR) in the
reference file by renaming it to *_mac_cr.* and change .gitattributes
accordingly.

Change-Id: Ibd9685613fc737146d67abcae19c67300343aa88
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Fawzi Mohamed 2021-11-03 15:39:00 +01:00
parent e89d85847b
commit 26e5200400
4 changed files with 62 additions and 195 deletions

1
.gitattributes vendored
View File

@ -1,4 +1,5 @@
*_crlf.* eol=crlf
*_mac_cr.* eol=cr
.tag export-subst
.gitignore export-ignore
.gitattributes export-ignore

View File

@ -1,157 +0,0 @@
/* 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 {
// This to id
// Also id. (line 2)
// This is the third id
// fourth id comment
id: foo
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: foo2
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!")
}

View File

@ -0,0 +1 @@
/* 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 { // 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 } // Orphan comment // Another orphan // More orphans property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3] property bool some_bool: false 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 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"; }() x: 3 // Very cool // This one to aFunc() function aFunc() { var x = 3; return x; } signal say(string name, bool caps) Component.onCompleted: console.log("Foo!") Text { required property string batman text: "Bla" signal boo(int count, int times, real duration) } myFavouriteThings: [ // This is an orphan // This is a cool text Text { }, // This is a cool rectangle Rectangle { } ] // This comment is related to the property animation PropertyAnimation on x { id: foo2 x: 3 y: x + 3 } }

View File

@ -40,6 +40,7 @@ class TestQmlformat: public QQmlDataTest
Q_OBJECT
public:
enum class RunOption { OnCopy, OrigToCopy };
TestQmlformat();
private Q_SLOTS:
@ -56,7 +57,8 @@ private Q_SLOTS:
private:
QString readTestFile(const QString &path);
QString runQmlformat(const QString &fileToFormat, QStringList args, bool shouldSucceed = true);
QString runQmlformat(const QString &fileToFormat, QStringList args, bool shouldSucceed = true,
RunOption rOption = RunOption::OnCopy);
QString m_qmlformatPath;
QStringList m_excludedDirs;
@ -209,51 +211,64 @@ void TestQmlformat::testFormat_data()
QTest::addColumn<QString>("file");
QTest::addColumn<QString>("fileFormatted");
QTest::addColumn<QStringList>("args");
QTest::addColumn<RunOption>("runOption");
QTest::newRow("example1")
QTest::newRow("example1") << "Example1.qml"
<< "Example1.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("example1 (tabs)")
<< "Example1.qml"
<< "Example1.formatted.qml" << QStringList {};
QTest::newRow("example1 (tabs)") << "Example1.qml"
<< "Example1.formatted.tabs.qml" << QStringList { "-t" };
<< "Example1.formatted.tabs.qml" << QStringList { "-t" } << RunOption::OnCopy;
QTest::newRow("example1 (two spaces)")
<< "Example1.qml"
<< "Example1.formatted.2spaces.qml" << QStringList { "-w", "2" };
QTest::newRow("annotation")
<< "Annotations.qml"
<< "Annotations.formatted.qml" << QStringList {};
<< "Example1.formatted.2spaces.qml" << QStringList { "-w", "2" } << RunOption::OnCopy;
QTest::newRow("annotation") << "Annotations.qml"
<< "Annotations.formatted.qml" << QStringList {}
<< RunOption::OnCopy;
QTest::newRow("front inline") << "FrontInline.qml"
<< "FrontInline.formatted.qml" << QStringList {};
<< "FrontInline.formatted.qml" << QStringList {}
<< RunOption::OnCopy;
QTest::newRow("if blocks") << "IfBlocks.qml"
<< "IfBlocks.formatted.qml" << QStringList {};
QTest::newRow("read-only properties") << "readOnlyProps.qml"
<< "readOnlyProps.formatted.qml" << QStringList {};
<< "IfBlocks.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("read-only properties")
<< "readOnlyProps.qml"
<< "readOnlyProps.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("states and transitions")
<< "statesAndTransitions.qml"
<< "statesAndTransitions.formatted.qml" << QStringList {};
QTest::newRow("large bindings") << "largeBindings.qml"
<< "largeBindings.formatted.qml" << QStringList {};
QTest::newRow("verbatim strings") << "verbatimString.qml"
<< "verbatimString.formatted.qml" << QStringList {};
QTest::newRow("inline components") << "inlineComponents.qml"
<< "inlineComponents.formatted.qml" << QStringList {};
<< "statesAndTransitions.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("large bindings")
<< "largeBindings.qml"
<< "largeBindings.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("verbatim strings")
<< "verbatimString.qml"
<< "verbatimString.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("inline components")
<< "inlineComponents.qml"
<< "inlineComponents.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("nested ifs") << "nestedIf.qml"
<< "nestedIf.formatted.qml" << QStringList {};
<< "nestedIf.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("QTBUG-85003") << "QtBug85003.qml"
<< "QtBug85003.formatted.qml" << QStringList {};
QTest::newRow("nested functions") << "nestedFunctions.qml"
<< "nestedFunctions.formatted.qml" << QStringList {};
QTest::newRow("multiline comments") << "multilineComment.qml"
<< "multilineComment.formatted.qml" << QStringList {};
<< "QtBug85003.formatted.qml" << QStringList {}
<< RunOption::OnCopy;
QTest::newRow("nested functions")
<< "nestedFunctions.qml"
<< "nestedFunctions.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("multiline comments")
<< "multilineComment.qml"
<< "multilineComment.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("for of") << "forOf.qml"
<< "forOf.formatted.qml" << QStringList {};
QTest::newRow("property names") << "propertyNames.qml"
<< "propertyNames.formatted.qml" << QStringList {};
<< "forOf.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("property names")
<< "propertyNames.qml"
<< "propertyNames.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("empty object") << "emptyObject.qml"
<< "emptyObject.formatted.qml" << QStringList {};
QTest::newRow("arrow functions") << "arrowFunctions.qml"
<< "arrowFunctions.formatted.qml" << QStringList {};
<< "emptyObject.formatted.qml" << QStringList {}
<< RunOption::OnCopy;
QTest::newRow("arrow functions")
<< "arrowFunctions.qml"
<< "arrowFunctions.formatted.qml" << QStringList {} << RunOption::OnCopy;
QTest::newRow("settings") << "settings/Example1.qml"
<< "settings/Example1.formatted.qml" << QStringList {};
<< "settings/Example1.formatted_mac_cr.qml" << QStringList {}
<< RunOption::OrigToCopy;
}
void TestQmlformat::testFormat()
@ -261,8 +276,9 @@ void TestQmlformat::testFormat()
QFETCH(QString, file);
QFETCH(QString, fileFormatted);
QFETCH(QStringList, args);
QFETCH(RunOption, runOption);
QCOMPARE(runQmlformat(testFile(file), args), readTestFile(fileFormatted));
QCOMPARE(runQmlformat(testFile(file), args, true, runOption), readTestFile(fileFormatted));
}
#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
@ -297,18 +313,24 @@ void TestQmlformat::testExample()
#endif
QString TestQmlformat::runQmlformat(const QString &fileToFormat, QStringList args,
bool shouldSucceed)
bool shouldSucceed, RunOption rOptions)
{
// Copy test file to temporary location
QTemporaryDir tempDir;
const QString tempFile = tempDir.path() + QDir::separator() + "to_format.qml";
QFile::copy(fileToFormat, tempFile);
args << QLatin1String("-i");
args << tempFile;
if (rOptions == RunOption::OnCopy) {
QFile::copy(fileToFormat, tempFile);
args << QLatin1String("-i");
args << tempFile;
} else {
args << fileToFormat;
}
auto verify = [&]() {
QProcess process;
if (rOptions == RunOption::OrigToCopy)
process.setStandardOutputFile(tempFile);
process.start(m_qmlformatPath, args);
QVERIFY(process.waitForFinished());
QCOMPARE(process.exitStatus(), QProcess::NormalExit);