tests/auto/linguist/lupdate/tst_lupdate.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 5 d3bac044e0f0
equal deleted inserted replaced
3:41300fa6a67c 4:3b1da2848fc7
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the Qt Linguist of the Qt Toolkit.
     7 ** This file is part of the Qt Linguist of the Qt Toolkit.
     8 **
     8 **
    37 **
    37 **
    38 ** $QT_END_LICENSE$
    38 ** $QT_END_LICENSE$
    39 **
    39 **
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include "testlupdate.h"
       
    43 #if CHECK_SIMTEXTH
    42 #if CHECK_SIMTEXTH
    44 #include "../shared/simtexth.h"
    43 #include "../shared/simtexth.h"
    45 #endif
    44 #endif
    46 
    45 
    47 #include <QtCore/QDir>
    46 #include <QtCore/QDir>
    53 
    52 
    54 class tst_lupdate : public QObject
    53 class tst_lupdate : public QObject
    55 {
    54 {
    56     Q_OBJECT
    55     Q_OBJECT
    57 public:
    56 public:
    58     tst_lupdate() { m_basePath = QDir::currentPath() + QLatin1String("/testdata/"); }
    57     tst_lupdate();
    59 
    58 
    60 private slots:
    59 private slots:
    61     void good_data();
    60     void good_data();
    62     void good();
    61     void good();
    63     void output_ts();
       
    64     void commandline_data();
    62     void commandline_data();
    65     void commandline();
    63     void commandline();
    66 #if CHECK_SIMTEXTH
    64 #if CHECK_SIMTEXTH
    67     void simtexth();
    65     void simtexth();
    68     void simtexth_data();
    66     void simtexth_data();
    69 #endif
    67 #endif
    70 
    68 
    71 private:
    69 private:
    72     TestLUpdate m_lupdate;
    70     QString m_cmdLupdate;
    73     QString m_basePath;
    71     QString m_basePath;
    74 
    72 
    75     void doCompare(const QStringList &actual, const QString &expectedFn, bool err);
    73     void doCompare(const QStringList &actual, const QString &expectedFn, bool err);
    76     void doCompare(const QString &actualFn, const QString &expectedFn, bool err);
    74     void doCompare(const QString &actualFn, const QString &expectedFn, bool err);
    77 };
    75 };
    78 
    76 
    79 
    77 
       
    78 tst_lupdate::tst_lupdate()
       
    79 {
       
    80     QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath);
       
    81     m_cmdLupdate = binPath + QLatin1String("/lupdate");
       
    82     m_basePath = QDir::currentPath() + QLatin1String("/testdata/");
       
    83 }
       
    84 
       
    85 static bool prepareMatch(const QString &expect, QString *tmpl, int *require, int *accept)
       
    86 {
       
    87     if (expect.startsWith(QLatin1Char('\\'))) {
       
    88         *tmpl = expect.mid(1);
       
    89         *require = *accept = 1;
       
    90     } else if (expect.startsWith(QLatin1Char('?'))) {
       
    91         *tmpl = expect.mid(1);
       
    92         *require = 0;
       
    93         *accept = 1;
       
    94     } else if (expect.startsWith(QLatin1Char('*'))) {
       
    95         *tmpl = expect.mid(1);
       
    96         *require = 0;
       
    97         *accept = INT_MAX;
       
    98     } else if (expect.startsWith(QLatin1Char('+'))) {
       
    99         *tmpl = expect.mid(1);
       
   100         *require = 1;
       
   101         *accept = INT_MAX;
       
   102     } else if (expect.startsWith(QLatin1Char('{'))) {
       
   103         int brc = expect.indexOf(QLatin1Char('}'), 1);
       
   104         if (brc < 0)
       
   105             return false;
       
   106         *tmpl = expect.mid(brc + 1);
       
   107         QString sub = expect.mid(1, brc - 1);
       
   108         int com = sub.indexOf(QLatin1Char(','));
       
   109         bool ok;
       
   110         if (com < 0) {
       
   111             *require = *accept = sub.toInt(&ok);
       
   112             return ok;
       
   113         } else {
       
   114             *require = sub.left(com).toInt();
       
   115             *accept = sub.mid(com + 1).toInt(&ok);
       
   116             if (!ok)
       
   117                 *accept = INT_MAX;
       
   118             return *accept >= *require;
       
   119         }
       
   120     } else {
       
   121         *tmpl = expect;
       
   122         *require = *accept = 1;
       
   123     }
       
   124     return true;
       
   125 }
       
   126 
    80 void tst_lupdate::doCompare(const QStringList &actual, const QString &expectedFn, bool err)
   127 void tst_lupdate::doCompare(const QStringList &actual, const QString &expectedFn, bool err)
    81 {
   128 {
    82     QFile file(expectedFn);
   129     QFile file(expectedFn);
    83     QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
   130     QVERIFY2(file.open(QIODevice::ReadOnly | QIODevice::Text), qPrintable(expectedFn));
    84     QStringList expected = QString(file.readAll()).trimmed().split('\n');
   131     QStringList expected = QString(file.readAll()).split('\n');
    85 
   132 
    86     int i = 0, ei = expected.size(), gi = actual.size();
   133     int ei = 0, ai = 0, em = expected.size(), am = actual.size();
    87     for (; ; i++) {
   134     int oei = 0, oai = 0, oem = em, oam = am;
    88         if (i == gi) {
   135     int require = 0, accept = 0;
    89             if (i == ei)
   136     QString tmpl;
    90                 return;
   137     forever {
    91             gi = 0;
   138         if (!accept) {
       
   139             oei = ei, oai = ai;
       
   140             if (ei == em) {
       
   141                 if (ai == am)
       
   142                     return;
       
   143                 break;
       
   144             }
       
   145             if (!prepareMatch(expected.at(ei++), &tmpl, &require, &accept))
       
   146                 QFAIL(qPrintable(QString("Malformed expected %1 at %3:%2")
       
   147                                  .arg(err ? "output" : "result").arg(ei).arg(expectedFn)));
       
   148         }
       
   149         if (ai == am) {
       
   150             if (require <= 0) {
       
   151                 accept = 0;
       
   152                 continue;
       
   153             }
    92             break;
   154             break;
    93         } else if (i == ei) {
   155         }
    94             ei = 0;
   156         if (err ? !QRegExp(tmpl).exactMatch(actual.at(ai)) : (actual.at(ai) != tmpl)) {
       
   157             if (require <= 0) {
       
   158                 accept = 0;
       
   159                 continue;
       
   160             }
       
   161             ei--;
       
   162             require = accept = 0;
       
   163             forever {
       
   164                 if (!accept) {
       
   165                     oem = em, oam = am;
       
   166                     if (ei == em)
       
   167                         break;
       
   168                     if (!prepareMatch(expected.at(--em), &tmpl, &require, &accept))
       
   169                         QFAIL(qPrintable(QString("Malformed expected %1 at %3:%2")
       
   170                                          .arg(err ? "output" : "result")
       
   171                                          .arg(em + 1).arg(expectedFn)));
       
   172                 }
       
   173                 if (ai == am || (err ? !QRegExp(tmpl).exactMatch(actual.at(am - 1)) :
       
   174                                        (actual.at(am - 1) != tmpl))) {
       
   175                     if (require <= 0) {
       
   176                         accept = 0;
       
   177                         continue;
       
   178                     }
       
   179                     break;
       
   180                 }
       
   181                 accept--;
       
   182                 require--;
       
   183                 am--;
       
   184             }
    95             break;
   185             break;
    96         } else {
   186         }
    97             QString act = actual.at(i);
   187         accept--;
    98             act.remove('\r');
   188         require--;
    99             if (err ? !QRegExp(expected.at(i)).exactMatch(act) :
   189         ai++;
   100                          (act != expected.at(i))) {
       
   101                 bool cond = true;
       
   102                 while (cond) {
       
   103                     act = actual.at(gi - 1);
       
   104                     act.remove('\r');
       
   105                     cond = (ei - 1) >= i && (gi - 1) >= i &&
       
   106                          (err ? QRegExp(expected.at(ei - 1)).exactMatch(act) :
       
   107                                 (act == expected.at(ei - 1)));
       
   108                     if (cond) {
       
   109                         ei--, gi--;
       
   110                     }
       
   111                 }
       
   112                 break;
       
   113             }
       
   114         }
       
   115     }
   190     }
   116     QByteArray diff;
   191     QByteArray diff;
   117     for (int j = qMax(0, i - 3); j < i; j++)
   192     for (int j = qMax(0, oai - 3); j < oai; j++)
   118         diff += expected.at(j) + '\n';
   193         diff += actual.at(j) + '\n';
   119     diff += "<<<<<<< got\n";
   194     diff += "<<<<<<< got\n";
   120     for (int j = i; j < gi; j++) {
   195     for (int j = oai; j < oam; j++) {
   121         diff += actual.at(j) + '\n';
   196         diff += actual.at(j) + '\n';
   122         if (j >= i + 5) {
   197         if (j >= oai + 5) {
   123             diff += "...\n";
   198             diff += "...\n";
   124             break;
   199             break;
   125         }
   200         }
   126     }
   201     }
   127     diff += "=========\n";
   202     diff += "=========\n";
   128     for (int j = i; j < ei; j++) {
   203     for (int j = oei; j < oem; j++) {
   129         diff += expected.at(j) + '\n';
   204         diff += expected.at(j) + '\n';
   130         if (j >= i + 5) {
   205         if (j >= oei + 5) {
   131             diff += "...\n";
   206             diff += "...\n";
   132             break;
   207             break;
   133         }
   208         }
   134     }
   209     }
   135     diff += ">>>>>>> expected\n";
   210     diff += ">>>>>>> expected\n";
   136     for (int j = ei; j < qMin(ei + 3, expected.size()); j++)
   211     for (int j = oam; j < qMin(oam + 3, actual.size()); j++)
   137         diff += expected.at(j) + '\n';
   212         diff += actual.at(j) + '\n';
   138     QFAIL(qPrintable((err ? "Output for " : "Result for ") + expectedFn + " does not meet expectations:\n" + diff));
   213     QFAIL(qPrintable((err ? "Output for " : "Result for ") + expectedFn + " does not meet expectations:\n" + diff));
   139 }
   214 }
   140 
   215 
   141 void tst_lupdate::doCompare(const QString &actualFn, const QString &expectedFn, bool err)
   216 void tst_lupdate::doCompare(const QString &actualFn, const QString &expectedFn, bool err)
   142 {
   217 {
   143     QFile afile(actualFn);
   218     QFile afile(actualFn);
   144     QVERIFY(afile.open(QIODevice::ReadOnly | QIODevice::Text));
   219     QVERIFY2(afile.open(QIODevice::ReadOnly | QIODevice::Text), qPrintable(actualFn));
   145     QStringList actual = QString(afile.readAll()).trimmed().split('\n');
   220     QStringList actual = QString(afile.readAll()).split('\n');
   146 
   221 
   147     doCompare(actual, expectedFn, err);
   222     doCompare(actual, expectedFn, err);
   148 }
   223 }
   149 
   224 
   150 void tst_lupdate::good_data()
   225 void tst_lupdate::good_data()
   165 void tst_lupdate::good()
   240 void tst_lupdate::good()
   166 {
   241 {
   167     QFETCH(QString, directory);
   242     QFETCH(QString, directory);
   168 
   243 
   169     QString dir = m_basePath + "good/" + directory;
   244     QString dir = m_basePath + "good/" + directory;
   170     QString expectedFile = dir + QLatin1String("/project.ts.result");
       
   171 
   245 
   172     qDebug() << "Checking...";
   246     qDebug() << "Checking...";
   173 
   247 
   174     // qmake will delete the previous one, to ensure that we don't do any merging....
   248     QString generatedtsfile(dir + QLatin1String("/project.ts"));
   175     QString generatedtsfile(QLatin1String("project.ts"));
   249 
   176 
       
   177     m_lupdate.setWorkingDirectory(dir);
       
   178     m_lupdate.qmake();
       
   179     // look for a command
   250     // look for a command
   180     QString lupdatecmd;
   251     QString lupdatecmd;
   181     QFile file(dir + "/lupdatecmd");
   252     QFile file(dir + "/lupdatecmd");
   182     if (file.exists()) {
   253     if (file.exists()) {
   183         QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
   254         QVERIFY2(file.open(QIODevice::ReadOnly | QIODevice::Text), qPrintable(file.fileName()));
   184         while (!file.atEnd()) {
   255         while (!file.atEnd()) {
   185             QByteArray cmdstring = file.readLine().simplified();
   256             QByteArray cmdstring = file.readLine().simplified();
   186             if (cmdstring.startsWith('#'))
   257             if (cmdstring.startsWith('#'))
   187                 continue;
   258                 continue;
   188             if (cmdstring.startsWith("lupdate")) {
   259             if (cmdstring.startsWith("lupdate")) {
   195             }
   266             }
   196         }
   267         }
   197         file.close();
   268         file.close();
   198     }
   269     }
   199 
   270 
   200     if (lupdatecmd.isEmpty()) {
   271     QFile::remove(generatedtsfile);
   201         lupdatecmd = QLatin1String("project.pro -ts project.ts");
   272     QString beforetsfile = generatedtsfile + QLatin1String(".before");
   202     }
   273     if (QFile::exists(beforetsfile))
       
   274         QVERIFY2(QFile::copy(beforetsfile, generatedtsfile), qPrintable(beforetsfile));
       
   275 
       
   276     if (lupdatecmd.isEmpty())
       
   277         lupdatecmd = QLatin1String("project.pro");
   203     lupdatecmd.prepend("-silent ");
   278     lupdatecmd.prepend("-silent ");
   204     m_lupdate.updateProFile(lupdatecmd);
   279 
       
   280     QProcess proc;
       
   281     proc.setWorkingDirectory(dir);
       
   282     proc.setProcessChannelMode(QProcess::MergedChannels);
       
   283     proc.start(m_cmdLupdate + ' ' + lupdatecmd, QIODevice::ReadWrite | QIODevice::Text);
       
   284     QVERIFY2(proc.waitForFinished(5000), qPrintable(lupdatecmd));
       
   285     QByteArray output = proc.readAll();
       
   286     QVERIFY2(proc.exitStatus() == QProcess::NormalExit,
       
   287              "\"lupdate " + lupdatecmd.toLatin1() + "\" crashed\n" + output);
       
   288     QVERIFY2(!proc.exitCode(),
       
   289              "\"lupdate " + lupdatecmd.toLatin1() + "\" exited with code " +
       
   290              QByteArray::number(proc.exitCode()) + "\n" + proc.readAll());
   205 
   291 
   206     // If the file expectedoutput.txt exists, compare the
   292     // If the file expectedoutput.txt exists, compare the
   207     // console output with the content of that file
   293     // console output with the content of that file
   208     QFile outfile(dir + "/expectedoutput.txt");
   294     QFile outfile(dir + "/expectedoutput.txt");
   209     if (outfile.exists()) {
   295     if (outfile.exists()) {
   210         QString errs = m_lupdate.getErrorMessages().at(1).trimmed();
   296         QStringList errslist = QString::fromLatin1(output).split(QLatin1Char('\n'));
   211         QStringList errslist = errs.split(QLatin1Char('\n'));
       
   212         doCompare(errslist, outfile.fileName(), true);
   297         doCompare(errslist, outfile.fileName(), true);
   213         if (QTest::currentTestFailed())
   298         if (QTest::currentTestFailed())
   214             return;
   299             return;
   215     }
   300     }
   216 
   301 
       
   302     QString expectedFile = generatedtsfile + QLatin1String(".result");
   217     doCompare(generatedtsfile, expectedFile, false);
   303     doCompare(generatedtsfile, expectedFile, false);
   218 }
       
   219 
       
   220 void tst_lupdate::output_ts()
       
   221 {
       
   222     QString dir = m_basePath + "output_ts";
       
   223     m_lupdate.setWorkingDirectory(dir);
       
   224 
       
   225     // look for a command
       
   226     QString lupdatecmd;
       
   227     QFile file(dir + "/lupdatecmd");
       
   228     if (file.exists()) {
       
   229         QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
       
   230         while (!file.atEnd()) {
       
   231         QByteArray cmdstring = file.readLine().simplified();
       
   232             if (cmdstring.startsWith('#'))
       
   233                 continue;
       
   234             if (cmdstring.startsWith("lupdate")) {
       
   235                 cmdstring.remove(0, 8);
       
   236                 lupdatecmd.append(cmdstring);
       
   237                 break;
       
   238             }
       
   239         }
       
   240         file.close();
       
   241     }
       
   242 
       
   243     QDir parsingDir(m_basePath + "output_ts");
       
   244 
       
   245     QString generatedtsfile =
       
   246         dir + QLatin1String("/toplevel/library/tools/translations/project.ts");
       
   247 
       
   248     QFile::remove(generatedtsfile);
       
   249 
       
   250     lupdatecmd.prepend("-silent ");
       
   251     m_lupdate.qmake();
       
   252     m_lupdate.updateProFile(lupdatecmd);
       
   253 
       
   254     // If the file expectedoutput.txt exists, compare the
       
   255     // console output with the content of that file
       
   256     QFile outfile(dir + "/expectedoutput.txt");
       
   257     if (outfile.exists()) {
       
   258         QString errs = m_lupdate.getErrorMessages().at(1).trimmed();
       
   259         QStringList errslist = errs.split(QLatin1Char('\n'));
       
   260         doCompare(errslist, outfile.fileName(), true);
       
   261         if (QTest::currentTestFailed())
       
   262             return;
       
   263     }
       
   264 
       
   265     doCompare(generatedtsfile, dir + QLatin1String("/project.ts.result"), false);
       
   266 }
   304 }
   267 
   305 
   268 void tst_lupdate::commandline_data()
   306 void tst_lupdate::commandline_data()
   269 {
   307 {
   270     QTest::addColumn<QString>("currentPath");
   308     QTest::addColumn<QString>("currentPath");
   283     QFETCH(QString, currentPath);
   321     QFETCH(QString, currentPath);
   284     QFETCH(QString, commandline);
   322     QFETCH(QString, commandline);
   285     QFETCH(QString, generatedtsfile);
   323     QFETCH(QString, generatedtsfile);
   286     QFETCH(QString, expectedtsfile);
   324     QFETCH(QString, expectedtsfile);
   287 
   325 
   288     m_lupdate.setWorkingDirectory(m_basePath + currentPath);
       
   289     QString generated =
   326     QString generated =
   290         m_basePath + currentPath + QLatin1Char('/') + generatedtsfile;
   327         m_basePath + currentPath + QLatin1Char('/') + generatedtsfile;
   291     QFile gen(generated);
   328     QFile gen(generated);
   292     if (gen.exists())
   329     if (gen.exists())
   293         QVERIFY(gen.remove());
   330         QVERIFY(gen.remove());
   294     if (!m_lupdate.run("-silent " + commandline))
   331     QProcess proc;
   295         qDebug() << m_lupdate.getErrorMessages().last();
   332     proc.setWorkingDirectory(m_basePath + currentPath);
       
   333     proc.setProcessChannelMode(QProcess::MergedChannels);
       
   334     proc.start(m_cmdLupdate + " -silent " + commandline, QIODevice::ReadWrite | QIODevice::Text);
       
   335     QVERIFY2(proc.waitForFinished(5000), qPrintable(commandline));
       
   336     QVERIFY2(proc.exitStatus() == QProcess::NormalExit,
       
   337              "\"lupdate -silent " + commandline.toLatin1() + "\" crashed\n" + proc.readAll());
       
   338     QVERIFY2(!proc.exitCode(),
       
   339              "\"lupdate -silent " + commandline.toLatin1() + "\" exited with code " +
       
   340              QByteArray::number(proc.exitCode()) + "\n" + proc.readAll());
   296 
   341 
   297     doCompare(generated, m_basePath + currentPath + QLatin1Char('/') + expectedtsfile, false);
   342     doCompare(generated, m_basePath + currentPath + QLatin1Char('/') + expectedtsfile, false);
   298 }
   343 }
   299 
   344 
   300 #if CHECK_SIMTEXTH
   345 #if CHECK_SIMTEXTH