tools/qtestlib/chart/reportgenerator.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include "reportgenerator.h"
       
    42 
       
    43 // Report generator file utility functions
       
    44 
       
    45 QList<QByteArray> readLines(const QString &fileName)
       
    46 {
       
    47     QList<QByteArray> lines;
       
    48     QFile f(fileName);
       
    49     f.open(QIODevice::ReadOnly | QIODevice::Text);
       
    50     while(!f.atEnd())
       
    51        lines.append(f.readLine());
       
    52     return lines;
       
    53 }
       
    54 
       
    55 void writeLines(const QString &fileName, const QList<QByteArray> &lines)
       
    56 {
       
    57     QFile f(fileName);
       
    58     f.open(QIODevice::WriteOnly | QIODevice::Text);
       
    59     foreach(const QByteArray line, lines)
       
    60        f.write(line);
       
    61 }
       
    62 
       
    63 void writeFile(const QString &fileName, const QByteArray &contents)
       
    64 {
       
    65     QFile f(fileName);
       
    66     f.open(QIODevice::WriteOnly | QIODevice::Append);
       
    67     f.write(contents);
       
    68 }
       
    69 
       
    70 // Report generator database utility functions
       
    71 
       
    72 QStringList select(const QString &field, const QString &tableName)
       
    73 {
       
    74     QSqlQuery query;
       
    75     query.prepare("SELECT DISTINCT " + field +" FROM " + tableName);
       
    76     bool ok  = query.exec(); 
       
    77     Q_UNUSED(ok);
       
    78 //    if (!ok)
       
    79 //        qDebug() << "select unique ok" << ok;
       
    80 
       
    81     QStringList values;
       
    82     while (query.next()) {
       
    83         values += query.value(0).toString();
       
    84     }
       
    85     return values;
       
    86 }
       
    87 
       
    88 QStringList selectUnique(const QString &field, const QString &tableName)
       
    89 {
       
    90     QSqlQuery query;
       
    91     query.prepare("SELECT DISTINCT " + field +" FROM " + tableName);
       
    92     bool ok  = query.exec(); 
       
    93     Q_UNUSED(ok);
       
    94 //    if (!ok)
       
    95 //        qDebug() << "select unique ok" << ok;
       
    96 
       
    97     QStringList values;
       
    98     while (query.next()) {
       
    99         values += query.value(0).toString();
       
   100     }
       
   101     return values;
       
   102 }
       
   103 
       
   104 QSqlQuery selectFromSeries(const QString &serie, const QString &column, const QString &tableName, const QString &seriesName)
       
   105 {
       
   106     QSqlQuery query;
       
   107     if (serie == QString())
       
   108         query.prepare("SELECT " + column + " FROM " + tableName);
       
   109     else
       
   110         query.prepare("SELECT " + column + " FROM " + tableName + " WHERE " + seriesName + "='" + serie + "'");
       
   111     /*bool ok  =*/ query.exec(); 
       
   112     
       
   113 
       
   114 //    qDebug() <<  "selectDataFromSeries ok?" <<  ok << query.size();
       
   115     return query;
       
   116 }
       
   117 
       
   118 int countDataFromSeries(const QString &serie, const QString &tableName, const QString &seriesName)
       
   119 {
       
   120 //    qDebug() << "count" << serie << "in" << tableName;
       
   121     QSqlQuery query;
       
   122     query.prepare("SELECT COUNT(Result) FROM " + tableName + " WHERE" + seriesName + "='" + serie + "'");
       
   123     bool ok  = query.exec(); 
       
   124     if (!ok) {
       
   125         qDebug() << "query fail" << query.lastError();
       
   126     }
       
   127     
       
   128     qDebug() <<  "countDataFromSeries ok?" <<  ok << query.size();
       
   129     query.next();
       
   130     return query.value(0).toInt();
       
   131 }
       
   132 
       
   133 // Report generator output utility functions
       
   134 
       
   135 QList<QByteArray> printData(const QString &tableName, const QString &seriesName, const QString &indexName)
       
   136 {
       
   137     QList<QByteArray> output;
       
   138     QStringList series = selectUnique(seriesName, tableName); 
       
   139 //    qDebug() << "series" << series;
       
   140     if (series.isEmpty())
       
   141         series+=QString();
       
   142     
       
   143     foreach (QString serie, series) {
       
   144         QSqlQuery data = selectFromSeries(serie, "Result", tableName, seriesName);
       
   145         QSqlQuery labels = selectFromSeries(serie, indexName, tableName, seriesName);
       
   146 
       
   147         QByteArray dataLine = "dataset.push({ data: [";
       
   148         int i = 0;
       
   149         while (data.next() && labels.next()) {
       
   150             QString label = labels.value(0).toString();
       
   151 
       
   152             QString labelString;
       
   153             bool ok;
       
   154             label.toInt(&ok);
       
   155             if (ok)
       
   156                 labelString = label;
       
   157         //    else
       
   158                 labelString = QString::number(i);
       
   159 
       
   160             dataLine += ("[" + labelString + ", " + data.value(0).toString() + "]");
       
   161             
       
   162             ++i;
       
   163             if (data.next()) {
       
   164                 dataLine += ", ";
       
   165                 data.previous();
       
   166             }
       
   167         }
       
   168         dataLine += "], label : \"" + serie + "\" });\n";
       
   169         output.append(dataLine);
       
   170     }
       
   171     return output;
       
   172 }
       
   173 
       
   174 // Determines if a line chart should be used. Returns true if the first label is numerical.
       
   175 bool useLineChart(const QString &tableName, const QString &seriesName, const QString &indexName)
       
   176 {
       
   177     QList<QByteArray> output;
       
   178     QStringList series = selectUnique(seriesName, tableName);
       
   179 	if (series.isEmpty())
       
   180 		return false;
       
   181 
       
   182     QSqlQuery data = selectFromSeries(series[0], indexName, tableName, seriesName);
       
   183 
       
   184     if (data.next()) {
       
   185         QString label = data.value(0).toString();
       
   186         bool ok;
       
   187         label.toDouble(&ok);
       
   188         return ok;
       
   189     }
       
   190 
       
   191     return false;
       
   192 }
       
   193 
       
   194 int countLabels(const QString &tableName, const QString &seriesName, const QString &indexName)
       
   195 {
       
   196     QStringList series = selectUnique(seriesName, tableName);
       
   197         if (series.isEmpty())
       
   198             return 0;
       
   199     QSqlQuery data = selectFromSeries(series[0], indexName, tableName, seriesName);
       
   200     int count = 0;
       
   201     while (data.next())
       
   202         count++;
       
   203 
       
   204     return count;
       
   205 }
       
   206 
       
   207 
       
   208 QList<QByteArray> printLabels(const QString &tableName, const QString &seriesName, const QString &indexName)
       
   209 {
       
   210     QList<QByteArray> output;
       
   211     QStringList series = selectUnique(seriesName, tableName);
       
   212 	if (series.isEmpty())
       
   213 		return QList<QByteArray>();
       
   214 
       
   215         QSqlQuery data = selectFromSeries(series[0], indexName, tableName, seriesName);
       
   216 
       
   217         int count = 0;
       
   218         while (data.next())
       
   219             count++;
       
   220 
       
   221         data.first(); data.previous();
       
   222 
       
   223         const int labelCount = 10;
       
   224         int skip = count / labelCount;
       
   225        
       
   226         QByteArray dataLine;
       
   227         int i = 0;
       
   228         while (data.next()) {
       
   229             dataLine += ("[" + QByteArray::number(i) + ",\"" + data.value(0).toString() + "\"]");
       
   230             ++i;
       
   231             if (data.next()) {
       
   232                 dataLine += ", ";
       
   233                 data.previous();
       
   234             }
       
   235 
       
   236             // skip labels.
       
   237             i += skip;
       
   238             for (int j = 0; j < skip; ++j)
       
   239                 data.next();
       
   240         }
       
   241         dataLine += "\n";
       
   242         output.append(dataLine);
       
   243     return output;
       
   244 }
       
   245 
       
   246 QByteArray printSeriesLabels(const QString &tableName, const QString &seriesColumnName)
       
   247 {
       
   248     QByteArray output;
       
   249     QStringList series = selectUnique(seriesColumnName, tableName);
       
   250  	if (series.isEmpty())
       
   251         return "[];\n";
       
   252 
       
   253     output += "[";
       
   254     
       
   255     foreach(const QString &serie, series) {
       
   256         output += "\"" + serie.toLocal8Bit() + "\",";
       
   257     }
       
   258     output.chop(1); //remove last comma
       
   259     output += "]\n";
       
   260     return output;
       
   261 }
       
   262 
       
   263 void addJavascript(QList<QByteArray> *output, const QString &fileName)
       
   264 {
       
   265     output->append("<script type=\"text/javascript\">\n");
       
   266     (*output) += readLines(fileName);
       
   267     output->append("</script>\n");
       
   268 }
       
   269 
       
   270 void addJavascript(QList<QByteArray> *output)
       
   271 {
       
   272     addJavascript(output, ":3rdparty/prototype.js");
       
   273     addJavascript(output, ":3rdparty/excanvas.js");
       
   274     addJavascript(output, ":3rdparty/flotr.js");
       
   275 }
       
   276 
       
   277 TempTable selectRows(const QString &sourceTable, const QString &column, const QString &value)
       
   278 {
       
   279     TempTable tempTable(resultsTable);
       
   280     
       
   281     QSqlQuery query;
       
   282     query.prepare("INSERT INTO " + tempTable.name() + " SELECT * FROM " + sourceTable +
       
   283                   " WHERE " + column + "='" + value + "'");
       
   284     execQuery(query);
       
   285     
       
   286 //    displayTable(tempTable.name());
       
   287     
       
   288     return tempTable;
       
   289 }
       
   290 
       
   291 TempTable mergeVersions(const QString &)
       
   292 {
       
   293 
       
   294 //  QtVersion - As series
       
   295 //  Result - (free)
       
   296 //  Idx - match
       
   297 //  TestName - match
       
   298 //  CaseName - match
       
   299 
       
   300 //  (Series - average)
       
   301 /*
       
   302     TempTable tempTable(resultsTable);
       
   303     QStringlist versions = selectUnique("QtVersions", sourceTable);
       
   304 
       
   305     QSqlQuery oneVersion = select(WHERE QtVersions = versions.at(0))
       
   306     while (oneVersion.next) {
       
   307         QSqlQuery otherversions = selectMatches(QStringList() << "TestName" << "TestCaseName" << "Idx")
       
   308         while (otherversions.next) {
       
   309             insert(temptable
       
   310         }
       
   311     }
       
   312 */
       
   313     return TempTable("");
       
   314 }
       
   315 
       
   316 QStringList fieldPriorityList = QStringList() << "Idx" << "Series" << "QtVersion";
       
   317 
       
   318 struct IndexSeriesFields
       
   319 {
       
   320     QString index;
       
   321     QString series;
       
   322 };
       
   323 
       
   324 IndexSeriesFields selectFields(const QString &table)
       
   325 {
       
   326     IndexSeriesFields fields;
       
   327     foreach (QString field, fieldPriorityList) {
       
   328 //        qDebug() << "unique" << field << selectUnique(field, table).count();
       
   329         QStringList rows = selectUnique(field, table);
       
   330 
       
   331         if (rows.count() <= 1 && rows.join("") == QString(""))
       
   332             continue;
       
   333 
       
   334         if (fields.index.isEmpty()) {
       
   335             fields.index = field;
       
   336             continue;
       
   337         }
       
   338 
       
   339         if (fields.series.isEmpty()) {
       
   340             fields.series = field;
       
   341             break;
       
   342         }
       
   343     }
       
   344     return fields;
       
   345 }
       
   346 
       
   347 TempTable selectTestCase(const QString &testCase, const QString &sourceTable)
       
   348 {
       
   349     return selectRows(sourceTable, QLatin1String("TestCaseName"), testCase);
       
   350 }
       
   351 
       
   352 QString field(const QSqlQuery &query, const QString &name)
       
   353 {
       
   354     return query.value(query.record().indexOf(name)).toString();
       
   355 }
       
   356 
       
   357 QSqlQuery selectAllResults(const QString &tableName)
       
   358 {
       
   359     QSqlQuery query;
       
   360     query.prepare("SELECT * FROM " + tableName);
       
   361     execQuery(query);
       
   362     return query;
       
   363 }
       
   364 
       
   365 void printTestCaseResults(const QString &testCaseName)
       
   366 {
       
   367 //    QStringList testCases = selectUnique("TestCaseName", "Results");
       
   368     qDebug() << "";
       
   369     qDebug() << "Results for benchmark" << testCaseName;
       
   370     TempTable temptable = selectTestCase(testCaseName, "Results");
       
   371     QSqlQuery query = selectAllResults(temptable.name());
       
   372     if (query.isActive() == false) {
       
   373         qDebug() << "No results";
       
   374         return;
       
   375     }
       
   376     
       
   377     query.next();
       
   378 
       
   379     if (field(query, "Idx") == QString()) {
       
   380         do {
       
   381             qDebug() << "Result:" << field(query, "result");
       
   382         } while (query.next());
       
   383     } else if (field(query, "Series") == QString()) {
       
   384         do {
       
   385             qDebug() << field(query, "Idx") << " : " << field(query, "result");
       
   386         } while (query.next());
       
   387     } else {
       
   388         do {
       
   389             qDebug() << field(query, "Series") << " - " <<  field(query, "Idx") << " : " << field(query, "result");
       
   390         } while (query.next());
       
   391     }
       
   392 
       
   393     qDebug() << "";
       
   394 }
       
   395 
       
   396 
       
   397 // ReportGenerator implementation
       
   398 
       
   399 ReportGenerator::ReportGenerator()
       
   400 {
       
   401 	m_colorScheme = QList<QByteArray>() << "#a03b3c" << "#3ba03a" << "#3a3ba0" << "#3aa09f" << "#39a06b" << "#a09f39";
       
   402 }
       
   403 
       
   404 
       
   405 void ReportGenerator::writeReport(const QString &tableName, const QString &fileName, bool combineQtVersions)
       
   406 {
       
   407     QStringList testCases = selectUnique("TestCaseName", tableName);
       
   408     QList<QByteArray> lines = readLines(":benchmark_template.html");
       
   409     QList<QByteArray> output;
       
   410 
       
   411     foreach(QByteArray line, lines) {
       
   412         if (line.contains("<! Chart Here>")) {
       
   413             foreach (const QString testCase, testCases) {
       
   414                 TempTable testCaseTable = selectTestCase(testCase, tableName);
       
   415                 output += writeChart(testCaseTable.name(), combineQtVersions);
       
   416             }
       
   417          } else if (line.contains("<! Title Here>")) {
       
   418             QStringList name = selectUnique("TestName", tableName);
       
   419             output += "Test: " + name.join("").toLocal8Bit();
       
   420          } else if (line.contains("<! Description Here>")) {
       
   421             output += selectUnique("TestTitle", tableName).join("").toLocal8Bit();
       
   422         } else if (line.contains("<! Javascript Here>")){
       
   423             addJavascript(&output);
       
   424          } else {
       
   425             output.append(line);
       
   426         }
       
   427     }
       
   428 
       
   429     m_fileName = fileName;
       
   430 
       
   431     writeLines(m_fileName, output);
       
   432     qDebug() << "Wrote report to" << m_fileName;
       
   433 }
       
   434 
       
   435 void ReportGenerator::writeReports()
       
   436 {
       
   437 /*
       
   438     QStringList versions = selectUnique("QtVersion", "Results");
       
   439 
       
   440  //   qDebug() << "versions" << versions;
       
   441 
       
   442     foreach (QString version, versions) {
       
   443         QString fileName = "results-"  + version  + ".html";
       
   444         TempTable versionTable = selectRows("Results", "QtVersion", version);
       
   445         writeReport(versionTable.name(), fileName, false);
       
   446     }
       
   447 */
       
   448     writeReport("Results", "results.html", false);
       
   449 }
       
   450 
       
   451 QString ReportGenerator::fileName()
       
   452 {
       
   453     return m_fileName;
       
   454 }
       
   455 
       
   456 QList<QByteArray> ReportGenerator::writeChart(const QString &tableName, bool combineQtVersions)
       
   457 {
       
   458     QSqlQuery query;
       
   459     query.prepare("SELECT TestName, Series, Idx, Result, ChartWidth, ChartHeight, Title, TestCaseName, ChartType, QtVersion FROM " + tableName);
       
   460     execQuery(query);
       
   461        
       
   462     QString seriesName;
       
   463     QString indexName;
       
   464     
       
   465     if (combineQtVersions) {
       
   466         IndexSeriesFields fields = selectFields(tableName);
       
   467         seriesName = fields.series;
       
   468         indexName = fields.index;
       
   469     } else {
       
   470         seriesName = "Series";
       
   471         indexName = "Idx";
       
   472     }
       
   473 
       
   474     QList<QByteArray> data = printData(tableName, seriesName, indexName);
       
   475     QList<QByteArray> labels = printLabels(tableName, seriesName, indexName);
       
   476     QByteArray seriesLabels = printSeriesLabels(tableName, seriesName);
       
   477     QByteArray useLineChartString = useLineChart(tableName, seriesName, indexName) ? "true" : "false" ;
       
   478 
       
   479     query.next();
       
   480     QString testName = query.value(0).toString();
       
   481     QSize size(query.value(4).toInt(), query.value(5).toInt());
       
   482 //    QString title = "Test Function: " + query.value(7).toString() + " - " +  query.value(6).toString();
       
   483     QString title = "Test Function: " + query.value(7).toString();
       
   484     QString chartId = "\"" + query.value(7).toString() + "\"";
       
   485     QString formId = "\"" + query.value(7).toString() + "form\"";
       
   486     QString chartTypeFormId = "\"" + query.value(7).toString() + "chartTypeform\"";
       
   487     QString scaleFormId = "\"" + query.value(7).toString() + "scaleform\"";
       
   488     QString type = query.value(8).toString();
       
   489 
       
   490     // Skip chart generation if there isn't enough data.
       
   491     if (countLabels(tableName, seriesName, indexName) < 2) {
       
   492         qDebug() << title.toAscii() << "No chartable data. (See the \"series\" test function"
       
   493                                     << "in examples/qtestlib/tutorial5 for an example.) ";
       
   494         return QList<QByteArray>() << title.toAscii() << " (no chartable data)"; // TODO: genrate text table here.
       
   495     }
       
   496 
       
   497 //    QString qtVersion = query.value(9).toString();
       
   498     query.previous();
       
   499 
       
   500     QString sizeString = "height=\"" + QString::number(size.height()) + "\" width=\"" + QString::number(size.width()) + "\"";
       
   501 
       
   502     QString fillString;
       
   503     if (type == "LineChart")
       
   504         fillString = "false";
       
   505     else
       
   506         fillString = "true";
       
   507 
       
   508     QByteArray colors = printColors(tableName, seriesName);
       
   509 
       
   510     QList<QByteArray> lines = readLines(":chart_template.html");
       
   511     QList<QByteArray> output;
       
   512 
       
   513     foreach(QByteArray line, lines) {
       
   514         if (line.contains("<! Test Name Here>")) {
       
   515             output.append(title.toLocal8Bit());
       
   516         } else if (line.contains("<! Chart ID Here>")) {
       
   517             output += chartId.toLocal8Bit();
       
   518         } else if (line.contains("<! Form ID Here>")) {
       
   519             output += formId.toLocal8Bit();
       
   520         } else if (line.contains("<! ChartTypeForm ID Here>")) {
       
   521             output += chartTypeFormId.toLocal8Bit();    
       
   522         } else if (line.contains("<! ScaleForm ID Here>")) {
       
   523             output += scaleFormId.toLocal8Bit();    
       
   524         } else if (line.contains("<! Size>")) {
       
   525             output += sizeString.toLocal8Bit();
       
   526         } else if (line.contains("<! ColorScheme Here>")) {
       
   527             output += colors;
       
   528         } else if (line.contains("<! Data Goes Here>")) {
       
   529             output += data;
       
   530         } else if (line.contains("<! Labels Go Here>")) {
       
   531             output += labels;
       
   532         } else if (line.contains("<! Use Line Chart Here>")) {
       
   533             output += useLineChartString + ";";
       
   534         } else if (line.contains("<! Chart Type Here>")) {
       
   535             output += "\"" + type.toLocal8Bit() + "\"";
       
   536         } else if (line.contains("<! Fill Setting Here>")) {
       
   537             output += fillString.toLocal8Bit();            
       
   538         } else if (line.contains("<! Series Labels Here>")) {
       
   539             output += seriesLabels;
       
   540         } else {
       
   541             output.append(line);
       
   542         }
       
   543     }
       
   544 
       
   545     return output;
       
   546 }
       
   547 
       
   548 QByteArray ReportGenerator::printColors(const QString &tableName, const QString &seriesName)
       
   549 {
       
   550     QByteArray colors;
       
   551     int i = 0;
       
   552     QStringList series = selectUnique(seriesName, tableName);
       
   553     foreach (const QString &serie, series) {
       
   554         colors.append("'" + serie.toLocal8Bit() + "': '" + m_colorScheme.at(i % m_colorScheme.count()) + "',\n");
       
   555         ++ i;
       
   556     }
       
   557     colors.chop(2); // remove last comma
       
   558     colors.append("\n");
       
   559     return colors;
       
   560 }
       
   561