source: trunk/tools/qtestlib/chart/reportgenerator.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 17.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41#include "reportgenerator.h"
42
43// Report generator file utility functions
44
45QList<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
55void 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
63void 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
72QStringList 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
88QStringList 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
104QSqlQuery 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
118int 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
135QList<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.
175bool 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
194int 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
208QList<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
246QByteArray 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
263void 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
270void 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
277TempTable 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
291TempTable 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
316QStringList fieldPriorityList = QStringList() << "Idx" << "Series" << "QtVersion";
317
318struct IndexSeriesFields
319{
320 QString index;
321 QString series;
322};
323
324IndexSeriesFields 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
347TempTable selectTestCase(const QString &testCase, const QString &sourceTable)
348{
349 return selectRows(sourceTable, QLatin1String("TestCaseName"), testCase);
350}
351
352QString field(const QSqlQuery &query, const QString &name)
353{
354 return query.value(query.record().indexOf(name)).toString();
355}
356
357QSqlQuery selectAllResults(const QString &tableName)
358{
359 QSqlQuery query;
360 query.prepare("SELECT * FROM " + tableName);
361 execQuery(query);
362 return query;
363}
364
365void 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
399ReportGenerator::ReportGenerator()
400{
401 m_colorScheme = QList<QByteArray>() << "#a03b3c" << "#3ba03a" << "#3a3ba0" << "#3aa09f" << "#39a06b" << "#a09f39";
402}
403
404
405void 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
435void 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
451QString ReportGenerator::fileName()
452{
453 return m_fileName;
454}
455
456QList<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
548QByteArray 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
Note: See TracBrowser for help on using the repository browser.