File indexing completed on 2024-05-12 04:39:05

0001 /*
0002     SPDX-License-Identifier: LGPL-2.0-only
0003 */
0004 
0005 #include "test_astyle.h"
0006 
0007 #include <QTest>
0008 #include <QDebug>
0009 #include <QStandardPaths>
0010 
0011 #include "../astyle_formatter.h"
0012 #include <util/formattinghelpers.h>
0013 
0014 QTEST_MAIN(TestAstyle)
0015 
0016 TestAstyle::~TestAstyle() = default;
0017 
0018 void TestAstyle::initTestCase()
0019 {
0020     QStandardPaths::setTestModeEnabled(true);
0021     m_formatter = std::make_unique<AStyleFormatter>();
0022     ///TODO: probably all settings should be covered by tests
0023     ///      or at least set so we can be sure about what we
0024     ///      actually test...
0025     m_formatter->setSpaceIndentationNoConversion(4);
0026 }
0027 
0028 void TestAstyle::renameVariable()
0029 {
0030     // think this:
0031     // int asdf = 1;
0032     // e.g. asdf was before something different and got renamed
0033     QString formattedSource = m_formatter->formatSource(
0034         QStringLiteral("asdf"), QStringLiteral("int "), QStringLiteral(" = 1;")
0035     );
0036     qDebug() << "formatted source:" << formattedSource;
0037     QCOMPARE(formattedSource, QString("asdf"));
0038 
0039     // int main() {
0040     //     if(asdf){}}
0041     formattedSource = m_formatter->formatSource(
0042         QStringLiteral("asdf"), QStringLiteral("int main(){\n     if("), QStringLiteral("){}}")
0043     );
0044     qDebug() << "formatted source:" << formattedSource;
0045     QCOMPARE(formattedSource, QString("asdf"));
0046 }
0047 
0048 void TestAstyle::testFuzzyMatching()
0049 {
0050     // Some formatting styles inserts "{" and "}" parens behind "ifs", or change comment styles
0051     // The actual text changes, thus it is difficult to match original and formatted text
0052 
0053     QString leftContext = QStringLiteral("void b() {/*some comment*/\nif( ");
0054     QString center = QStringLiteral("a[   0]");
0055     QString rightContext =  QStringLiteral(" ) q;\n }\n");
0056     QString text = leftContext + center + rightContext;
0057     QString formatted = QStringLiteral("void b() {// some comment\n    if( a[0] ) {\n        q;\n    }\n }\n");
0058     QString extracted = KDevelop::extractFormattedTextFromContext( formatted, text, QString(), QString() );
0059     QCOMPARE( extracted, formatted );
0060     
0061     extracted = KDevelop::extractFormattedTextFromContext( formatted, center, leftContext, rightContext );
0062     qDebug() << "extracted" << extracted << "formatted" << formatted;
0063     QCOMPARE( extracted, QString("a[0]") );
0064 
0065     rightContext = QStringLiteral("\nvoid g() {}");
0066     extracted = KDevelop::extractFormattedTextFromContext(formatted + rightContext, text, QString(), rightContext);
0067     QCOMPARE(extracted, formatted);
0068 }
0069 
0070 void TestAstyle::testTabMatching()
0071 {
0072     // Some formatting styles inserts "{" and "}" parens behind "ifs", or change comment styles
0073     // The actual text changes, thus it is difficult to match original and formatted text
0074 
0075 {
0076     // Mismatch: There is a preceding tab, but the formatter replaces the tab with spaces
0077     // The tab is matched with 2 spaces, since we set tab-width 2
0078     QString extracted = KDevelop::extractFormattedTextFromContext(
0079         QStringLiteral("class C {\n  class A;\n}\n"),
0080         QStringLiteral("class A;"), QStringLiteral("class C {\n "), QStringLiteral("\n}\n"), 2 );
0081     QCOMPARE( extracted, QString("class A;") );
0082     
0083     // Two tabs are inserted insead of 1
0084     extracted = KDevelop::extractFormattedTextFromContext(
0085         QStringLiteral("class C {\n     class A;\n}\n"),
0086         QStringLiteral("class A;"), QStringLiteral("class C {\n "), QStringLiteral("\n}\n"), 2 );
0087     QCOMPARE( extracted, QString("  class A;") );
0088     
0089     // One space is inserted behind the tab
0090     extracted = KDevelop::extractFormattedTextFromContext(
0091         QStringLiteral("class C {\n  class A;\n}\n"),
0092         QStringLiteral("class A;"), QStringLiteral("class C {\n "), QStringLiteral("\n}\n"), 2 );
0093     QCOMPARE( extracted, QString(" class A;") );
0094 
0095     // Two tabs are inserted, with 2 preceding whitespaces
0096     // Add only 1 tab
0097     extracted = KDevelop::extractFormattedTextFromContext(
0098         QStringLiteral("class C {\n     class A;\n}\n"),
0099         QStringLiteral("class A;"), QStringLiteral("class C {\n  "), QStringLiteral("\n}\n"), 2 );
0100     QCOMPARE( extracted, QString("  class A;") );
0101 
0102     extracted = KDevelop::extractFormattedTextFromContext(
0103         QStringLiteral("class C {\n          class A;\n}\n"),
0104         QStringLiteral("class A;"), QStringLiteral("class C {\n     "), QStringLiteral("\n}\n"), 4 );
0105     QCOMPARE( extracted, QString("  class A;") );
0106 }
0107 {
0108     // Already correctly formatted
0109     QString leftContext = QStringLiteral("void b() {\n c = 4;\n ");
0110     QString center = QStringLiteral("a = 3;");
0111     QString rightContext =  QStringLiteral("\n b = 5;\n }\n");
0112     QString text = leftContext + center + rightContext;
0113     QString formatted = QStringLiteral("void b() {\n    c = 4;\n    a = 3;\n    b = 5;\n }\n");
0114     QString extracted = KDevelop::extractFormattedTextFromContext( formatted, text, QString(), QString() );
0115     QCOMPARE( extracted, formatted );
0116     
0117     extracted = KDevelop::extractFormattedTextFromContext( formatted, center, leftContext, rightContext );
0118     QCOMPARE( extracted, QString("a = 3;") );
0119 }
0120 {
0121     QString leftContext = QStringLiteral("void b() {\n c = 4;\n");
0122     QString center = QStringLiteral("a = 3;\n");
0123     QString rightContext =  QStringLiteral("b = 5;\n }\n");
0124     QString text = leftContext + center + rightContext;
0125     QString formatted = QStringLiteral("void b() {\n    c = 4;\n    a = 3;\n    b = 5;\n }\n");
0126     QString extracted = KDevelop::extractFormattedTextFromContext( formatted, text, QString(), QString() );
0127     QCOMPARE( extracted, formatted );
0128     
0129     extracted = KDevelop::extractFormattedTextFromContext( formatted, center, leftContext, rightContext );
0130     QCOMPARE( extracted, QString("  a = 3;\n    ") );
0131 }
0132 }
0133 
0134 void TestAstyle::overrideHelper()
0135 {
0136     // think this:
0137     // virtual void asdf();
0138     // gets included into a class
0139 
0140     // test1: not indented
0141     QString formattedSource = m_formatter->formatSource(
0142         QStringLiteral("virtual void asdf();"), QStringLiteral("class asdf {\n    int bar();\n"), QStringLiteral("\n};")
0143     );
0144     qDebug() << "formatted source:" << formattedSource;
0145     QCOMPARE(formattedSource, QString("    virtual void asdf();"));
0146 
0147     // test2: already indented
0148     formattedSource = m_formatter->formatSource(
0149         QStringLiteral("virtual void asdf();"), QStringLiteral("class asdf {\n    int bar();\n    "), QStringLiteral("\n};")
0150     );
0151     qDebug() << "formatted source:" << formattedSource;
0152     QCOMPARE(formattedSource, QString("virtual void asdf();"));
0153 }
0154 
0155 void TestAstyle::varTypeAssistant()
0156 {
0157     // think this:
0158     // asdf = 1;
0159     // and you execute the assistant to get:
0160     // int asdf = 1;
0161 
0162     // test1: already indented
0163     QString formattedSource = m_formatter->formatSource(
0164         QStringLiteral("int "), QStringLiteral("int main() {\n    "), QStringLiteral("asdf = 1;\n}\n")
0165     );
0166     qDebug() << "formatted source:" << formattedSource;
0167     QCOMPARE(formattedSource, QString("int "));
0168 
0169     // test2: not yet indented
0170     formattedSource = m_formatter->formatSource(
0171         QStringLiteral("int "), QStringLiteral("int main() {\n"), QStringLiteral("asdf = 1;\n}\n")
0172     );
0173     qDebug() << "formatted source:" << formattedSource;
0174     QCOMPARE(formattedSource, QString("    int "));
0175 
0176 }
0177 
0178 void TestAstyle::testMultipleFormatters()
0179 {
0180     // just test that multiple formatters can exist at the same time
0181     auto* formatter1 = new AStyleFormatter;
0182     auto* formatter2 = new AStyleFormatter;
0183     delete formatter1;
0184     delete formatter2;
0185 }
0186 
0187 void TestAstyle::testMacroFormatting()
0188 {
0189     AStyleFormatter fmt;
0190     fmt.setSpaceIndentationNoConversion(2);
0191     fmt.setPreprocessorIndent(true);
0192     QString formatted = fmt.formatSource(QStringLiteral("#define asdf\\\nfoobar\n"));
0193     QCOMPARE(formatted, QString("#define asdf\\\n  foobar\n"));
0194 }
0195 
0196 void TestAstyle::testContext()
0197 {
0198     auto* formatter = new AStyleFormatter;
0199     formatter->setBracketFormatMode(astyle::LINUX_MODE);
0200     formatter->setParensInsidePaddingMode(true);
0201     formatter->setBlockIndent(true);
0202     // We enable break-blocks mode, so that we can test the newline matching
0203     formatter->setBreakBlocksMode(true);
0204     formatter->setBreakClosingHeaderBlocksMode(true);
0205     formatter->setParensUnPaddingMode(true);
0206     
0207     QString leftContext = QStringLiteral("int main() {\n");
0208     QString rightContext = QStringLiteral(";\n}\n");
0209     
0210     /// Newline tests
0211     
0212     QString formattedSource = formatter->formatSource(
0213         QStringLiteral(" int a;\n"), leftContext, "int b;" + rightContext );
0214     
0215 //     qDebug() << formattedSource;
0216     // Adjust indentation
0217     QCOMPARE(formattedSource, QString("    int a;\n    "));
0218     
0219     formattedSource = formatter->formatSource(
0220         QStringLiteral(" int a;\n"), leftContext + " ", "   int b;" + rightContext );
0221     
0222 //     qDebug() << formattedSource;
0223     QCOMPARE(formattedSource, QString("   int a;\n "));
0224     
0225     /// "if(a);" is interpreted as own block, so due to the "break blocks" option,
0226     /// astyle breaks these blocks with a newline in between.
0227     formattedSource = formatter->formatSource(
0228         QStringLiteral("  if(a); "), leftContext + " if(a); ", " if(a);" + rightContext );
0229     
0230 //     qDebug() << formattedSource;
0231     QCOMPARE(formattedSource, QString("\n\n    if( a );\n\n   "));
0232 
0233     formattedSource = formatter->formatSource(
0234         QStringLiteral("  if(a); "), leftContext + " if(a);\n", " \n if(a);" + rightContext );
0235     
0236 //     qDebug() << formattedSource;
0237     QCOMPARE(formattedSource, QString("\n    if( a );\n"));
0238 
0239     formattedSource = formatter->formatSource(
0240         QStringLiteral("  if(a)\na; "), leftContext + " if(a);\n", " \n\n if(a);" + rightContext );
0241     
0242 //     qDebug() << formattedSource;
0243     // Adjust indentation, successor already partially indentend
0244     QCOMPARE(formattedSource, QString("\n    if( a )\n        a;"));
0245     
0246     /// Whitespace tests
0247     
0248     formattedSource = formatter->formatSource(
0249         QStringLiteral("int "), leftContext + "  ", rightContext );
0250     
0251     // 2 whitespaces are already in the context, so add only 2
0252 //     qDebug() << "formatted source:" << formattedSource;
0253     QCOMPARE(formattedSource, QString("  int "));
0254 
0255     formattedSource = formatter->formatSource(
0256         QStringLiteral("q"), leftContext + "  if(", ")" + rightContext );
0257     
0258     // Padding was added around both parens
0259     QCOMPARE(formattedSource, QString(" q "));
0260 
0261     formattedSource = formatter->formatSource(
0262         QStringLiteral("q"), leftContext + "  if( ", " )" + rightContext );
0263     
0264     // Padding already existed around both parens
0265     QCOMPARE(formattedSource, QString("q"));
0266 
0267     formattedSource = formatter->formatSource(
0268         QStringLiteral(" q "), leftContext + "  if(", "   )" + rightContext );
0269     
0270 //     qDebug() << formattedSource;
0271     // No padding on left, too much padding on right
0272     QCOMPARE(formattedSource, QString(" q"));
0273 
0274     formattedSource = formatter->formatSource(
0275         QStringLiteral("   "), leftContext + "  if(q", ")" + rightContext );
0276     
0277 //     qDebug() << formattedSource;
0278     // Normalize padding: from 3 to 1
0279     QCOMPARE(formattedSource, QString(" "));
0280     
0281     formattedSource = formatter->formatSource(
0282         QString(), leftContext + "  if(", "q )" + rightContext );
0283     
0284 //     qDebug() << formattedSource;
0285     // Normalize padding: from 0 to 1
0286     QCOMPARE(formattedSource, QString(" "));
0287     
0288     formattedSource = formatter->formatSource(
0289         QStringLiteral(" "), leftContext + "  if(   ", "q )" + rightContext );
0290     
0291 //     qDebug() << formattedSource;
0292     // Reduce padding as much as possible
0293     QCOMPARE(formattedSource, QString());
0294     
0295     delete formatter;
0296 }
0297 
0298 void TestAstyle::testTabIndentation()
0299 {
0300     AStyleFormatter formatter;
0301     formatter.setTabIndentation(2, false);
0302 
0303     const QString initial(QStringLiteral("int a() {\n  return 0;\n}\n"));
0304     const QString expected(QStringLiteral("int a() {\n\treturn 0;\n}\n"));
0305     const QString formatted = formatter.formatSource(initial);
0306     QCOMPARE(formatted, expected);
0307 }
0308 
0309 void TestAstyle::testForeach()
0310 {
0311     AStyleFormatter formatter;
0312     QVERIFY(formatter.predefinedStyle("KDELibs"));
0313 
0314     const QString initial(QStringLiteral("int a(){QList<int> v;\n    foreach(int i,v){\nreturn i;}}\n"));
0315     const QString expected(QStringLiteral("int a()\n{\n    QList<int> v;\n    foreach (int i, v) {\n        return i;\n    }\n}\n"));
0316     const QString formatted = formatter.formatSource(initial);
0317     QCOMPARE(formatted, expected);
0318 }
0319 
0320 void TestAstyle::testPointerAlignment()
0321 {
0322     AStyleFormatter formatter;
0323     formatter.setPointerAlignment(astyle::PTR_ALIGN_NAME);
0324 
0325     const QString initial(QStringLiteral("int* a;\nint * b;\nint *c;\nint & d;\nconst double * const e;\n"));
0326     const QString expected(QStringLiteral("int *a;\nint *b;\nint *c;\nint &d;\nconst double *const e;\n"));
0327     const QString formatted = formatter.formatSource(initial);
0328     QCOMPARE(formatted, expected);
0329 }
0330 
0331 void TestAstyle::testKdeFrameworks()
0332 {
0333     AStyleFormatter formatter;
0334     QVERIFY(formatter.predefinedStyle("KDELibs"));
0335 
0336     QFETCH(QString, initial);
0337     QFETCH(QString, leftContext);
0338     QFETCH(QString, rightContext);
0339     QFETCH(QString, expected);
0340 
0341     const QString formatted = formatter.formatSource(initial, leftContext, rightContext);
0342     QCOMPARE(formatted, expected);
0343 }
0344 
0345 void TestAstyle::testKdeFrameworks_data()
0346 {
0347     QTest::addColumn<QString>("initial");
0348     QTest::addColumn<QString>("leftContext");
0349     QTest::addColumn<QString>("rightContext");
0350     QTest::addColumn<QString>("expected");
0351 
0352     const QString leftContext = QStringLiteral("int main()\n{\n");
0353     const QString rightContext = QStringLiteral("\n}\n");
0354 
0355     QString initial = QStringLiteral("\t int a;");
0356     QString expected = QStringLiteral("    int a;");
0357     QTest::newRow("indentation") << initial << leftContext << rightContext << expected;
0358 
0359     initial = QStringLiteral("if(1);\n while (false);\nfor(int i=0; i<1; i++);\n");
0360     expected = QStringLiteral("    if (1);\n    while (false);\n    for (int i = 0; i < 1; i++);\n");
0361     QTest::newRow("space-after-keyword") << initial << leftContext << rightContext << expected;
0362 
0363     initial = QStringLiteral("int* a;\nint * b;\nint *c;\nint & d;\nconst double * const e;\n");
0364     expected = QStringLiteral("int *a;\nint *b;\nint *c;\nint &d;\nconst double *const e;\n");
0365     QTest::newRow("pointer-alignment") << initial << QString() << QString() << expected;
0366 
0367     initial = QStringLiteral("if (true)\n{\n}\n");
0368     expected = QStringLiteral("    if (true) {\n    }\n");
0369     QTest::newRow("brace-on-same-line") << initial << leftContext << rightContext << expected;
0370 
0371     initial = QStringLiteral("void foo(void) {\n}\nclass a {\n};\nnamespace c\n{\n}\n");
0372     expected = QStringLiteral("void foo(void)\n{\n}\nclass a\n{\n};\nnamespace c\n{\n}\n");
0373     QTest::newRow("brace-on-new-line") << initial << QString() << QString() << expected;
0374 
0375     initial = QStringLiteral("switch (myEnum)\n{\ncase Value1:\ndoSomething();}\n");
0376     expected = QStringLiteral("    switch (myEnum) {\n    case Value1:\n        doSomething();\n    }\n");
0377     QTest::newRow("switch-statement") << initial << leftContext << rightContext << expected;
0378 }
0379 
0380 #include "moc_test_astyle.cpp"