Enable multiple instances of QAbstractTestLogger.
Previously QAbstractTestLogger used a global variable for the file pointer to which it was writing test output. This effectively meant that only one instance of this or its derived classes could exist at any time. This commit moves the file pointer inside the class, so that multiple loggers can exist at the same time. This means that the outputString() method can no longer be static, which in turn means that several functions used by QPlainTestLogger need to move from the QTest namespace into the class, and also that QTestBasicStreamer must hold a non-const pointer to its associated logger instead of a const pointer. Task-number: QTBUG-20615 Change-Id: If941f1f9399cf20fb93e3e87f3390bceeca1cbfc Reviewed-on: http://codereview.qt.nokia.com/3576 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
This commit is contained in:
parent
dc7b2b8d9c
commit
e8e9b62f72
@ -54,32 +54,27 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QTest
|
||||
{
|
||||
static FILE *stream = 0;
|
||||
}
|
||||
|
||||
void QAbstractTestLogger::outputString(const char *msg)
|
||||
{
|
||||
QTEST_ASSERT(QTest::stream);
|
||||
QTEST_ASSERT(stream);
|
||||
|
||||
::fputs(msg, QTest::stream);
|
||||
::fflush(QTest::stream);
|
||||
::fputs(msg, stream);
|
||||
::fflush(stream);
|
||||
}
|
||||
|
||||
void QAbstractTestLogger::startLogging(const char *filename)
|
||||
{
|
||||
QTEST_ASSERT(!QTest::stream);
|
||||
QTEST_ASSERT(!stream);
|
||||
|
||||
if (!filename) {
|
||||
QTest::stream = stdout;
|
||||
stream = stdout;
|
||||
return;
|
||||
}
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE)
|
||||
if (::fopen_s(&QTest::stream, filename, "wt")) {
|
||||
if (::fopen_s(&stream, filename, "wt")) {
|
||||
#else
|
||||
QTest::stream = ::fopen(filename, "wt");
|
||||
if (!QTest::stream) {
|
||||
stream = ::fopen(filename, "wt");
|
||||
if (!stream) {
|
||||
#endif
|
||||
printf("Unable to open file for logging: %s", filename);
|
||||
::exit(1);
|
||||
@ -88,9 +83,9 @@ void QAbstractTestLogger::startLogging(const char *filename)
|
||||
|
||||
void QAbstractTestLogger::stopLogging()
|
||||
{
|
||||
QTEST_ASSERT(QTest::stream);
|
||||
if (QTest::stream != stdout) {
|
||||
fclose(QTest::stream);
|
||||
QTEST_ASSERT(stream);
|
||||
if (stream != stdout) {
|
||||
fclose(stream);
|
||||
} else {
|
||||
#ifdef Q_OS_SYMBIAN
|
||||
// Convenience sleep for Symbian and TRK. Without this sleep depending on the timing the
|
||||
@ -99,7 +94,7 @@ void QAbstractTestLogger::stopLogging()
|
||||
User::AfterHighRes(2*1000*1000);
|
||||
#endif
|
||||
}
|
||||
QTest::stream = 0;
|
||||
stream = 0;
|
||||
}
|
||||
|
||||
namespace QTest
|
||||
|
@ -54,6 +54,7 @@
|
||||
//
|
||||
|
||||
#include <qglobal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -79,7 +80,7 @@ public:
|
||||
Info
|
||||
};
|
||||
|
||||
QAbstractTestLogger() {}
|
||||
QAbstractTestLogger() : stream(0) {}
|
||||
virtual ~QAbstractTestLogger() {}
|
||||
|
||||
virtual void startLogging(const char *filename);
|
||||
@ -97,7 +98,10 @@ public:
|
||||
|
||||
virtual void registerRandomSeed(unsigned int seed) = 0;
|
||||
|
||||
static void outputString(const char *msg);
|
||||
void outputString(const char *msg);
|
||||
|
||||
private:
|
||||
FILE *stream;
|
||||
};
|
||||
|
||||
struct QTestCharBuffer
|
||||
|
@ -115,81 +115,6 @@ namespace QTest {
|
||||
return "??????";
|
||||
}
|
||||
|
||||
static void outputMessage(const char *str)
|
||||
{
|
||||
#if defined(Q_OS_WINCE)
|
||||
QString strUtf16 = QString::fromLatin1(str);
|
||||
const int maxOutputLength = 255;
|
||||
do {
|
||||
QString tmp = strUtf16.left(maxOutputLength);
|
||||
OutputDebugString((wchar_t*)tmp.utf16());
|
||||
strUtf16.remove(0, maxOutputLength);
|
||||
} while (!strUtf16.isEmpty());
|
||||
if (QTestLog::outputFileName())
|
||||
#elif defined(Q_OS_WIN)
|
||||
EnterCriticalSection(&outputCriticalSection);
|
||||
// OutputDebugString is not threadsafe
|
||||
OutputDebugStringA(str);
|
||||
LeaveCriticalSection(&outputCriticalSection);
|
||||
#elif defined(Q_OS_SYMBIAN)
|
||||
// RDebug::Print has a cap of 256 characters so break it up
|
||||
TPtrC8 ptr(reinterpret_cast<const TUint8*>(str));
|
||||
_LIT(format, "[QTestLib] %S");
|
||||
const int maxBlockSize = 256 - ((const TDesC &)format).Length();
|
||||
HBufC* hbuffer = HBufC::New(maxBlockSize);
|
||||
if(hbuffer) {
|
||||
for (int i = 0; i < ptr.Length(); i += maxBlockSize) {
|
||||
int size = Min(maxBlockSize, ptr.Length() - i);
|
||||
hbuffer->Des().Copy(ptr.Mid(i, size));
|
||||
RDebug::Print(format, hbuffer);
|
||||
}
|
||||
delete hbuffer;
|
||||
}
|
||||
else {
|
||||
// fast, no allocations, but truncates silently
|
||||
RDebug::RawPrint(format);
|
||||
TPtrC8 ptr(reinterpret_cast<const TUint8*>(str));
|
||||
RDebug::RawPrint(ptr);
|
||||
RDebug::RawPrint(_L8("\n"));
|
||||
}
|
||||
#endif
|
||||
QAbstractTestLogger::outputString(str);
|
||||
}
|
||||
|
||||
static void printMessage(const char *type, const char *msg, const char *file = 0, int line = 0)
|
||||
{
|
||||
QTEST_ASSERT(type);
|
||||
QTEST_ASSERT(msg);
|
||||
|
||||
QTestCharBuffer buf;
|
||||
|
||||
const char *fn = QTestResult::currentTestFunction() ? QTestResult::currentTestFunction()
|
||||
: "UnknownTestFunc";
|
||||
const char *tag = QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "";
|
||||
const char *gtag = QTestResult::currentGlobalDataTag()
|
||||
? QTestResult::currentGlobalDataTag()
|
||||
: "";
|
||||
const char *filler = (tag[0] && gtag[0]) ? ":" : "";
|
||||
if (file) {
|
||||
QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n"
|
||||
#ifdef Q_OS_WIN
|
||||
"%s(%d) : failure location\n"
|
||||
#else
|
||||
" Loc: [%s(%d)]\n"
|
||||
#endif
|
||||
, type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
|
||||
msg[0] ? " " : "", msg, file, line);
|
||||
} else {
|
||||
QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n",
|
||||
type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
|
||||
msg[0] ? " " : "", msg);
|
||||
}
|
||||
// In colored mode, printf above stripped our nonprintable control characters.
|
||||
// Put them back.
|
||||
memcpy(buf.data(), type, strlen(type));
|
||||
outputMessage(buf.data());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static int countSignificantDigits(T num)
|
||||
{
|
||||
@ -274,74 +199,149 @@ namespace QTest {
|
||||
int size = result.count();
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
// static void printBenchmarkResult(const char *bmtag, int value, int iterations)
|
||||
static void printBenchmarkResult(const QBenchmarkResult &result)
|
||||
{
|
||||
const char *bmtag = QTest::benchmarkResult2String();
|
||||
|
||||
char buf1[1024];
|
||||
QTest::qt_snprintf(
|
||||
buf1, sizeof(buf1), "%s: %s::%s",
|
||||
bmtag,
|
||||
QTestResult::currentTestObjectName(),
|
||||
result.context.slotName.toAscii().data());
|
||||
|
||||
char bufTag[1024];
|
||||
bufTag[0] = 0;
|
||||
QByteArray tag = result.context.tag.toAscii();
|
||||
if (tag.isEmpty() == false) {
|
||||
QTest::qt_snprintf(bufTag, sizeof(bufTag), ":\"%s\"", tag.data());
|
||||
void QPlainTestLogger::outputMessage(const char *str)
|
||||
{
|
||||
#if defined(Q_OS_WINCE)
|
||||
QString strUtf16 = QString::fromLatin1(str);
|
||||
const int maxOutputLength = 255;
|
||||
do {
|
||||
QString tmp = strUtf16.left(maxOutputLength);
|
||||
OutputDebugString((wchar_t*)tmp.utf16());
|
||||
strUtf16.remove(0, maxOutputLength);
|
||||
} while (!strUtf16.isEmpty());
|
||||
if (QTestLog::outputFileName())
|
||||
#elif defined(Q_OS_WIN)
|
||||
EnterCriticalSection(&QTest::outputCriticalSection);
|
||||
// OutputDebugString is not threadsafe
|
||||
OutputDebugStringA(str);
|
||||
LeaveCriticalSection(&QTest::outputCriticalSection);
|
||||
#elif defined(Q_OS_SYMBIAN)
|
||||
// RDebug::Print has a cap of 256 characters so break it up
|
||||
TPtrC8 ptr(reinterpret_cast<const TUint8*>(str));
|
||||
_LIT(format, "[QTestLib] %S");
|
||||
const int maxBlockSize = 256 - ((const TDesC &)format).Length();
|
||||
HBufC* hbuffer = HBufC::New(maxBlockSize);
|
||||
if (hbuffer) {
|
||||
for (int i = 0; i < ptr.Length(); i += maxBlockSize) {
|
||||
int size = Min(maxBlockSize, ptr.Length() - i);
|
||||
hbuffer->Des().Copy(ptr.Mid(i, size));
|
||||
RDebug::Print(format, hbuffer);
|
||||
}
|
||||
|
||||
|
||||
char fillFormat[8];
|
||||
int fillLength = 5;
|
||||
QTest::qt_snprintf(
|
||||
fillFormat, sizeof(fillFormat), ":\n%%%ds", fillLength);
|
||||
char fill[1024];
|
||||
QTest::qt_snprintf(fill, sizeof(fill), fillFormat, "");
|
||||
|
||||
const char * unitText = QTest::benchmarkMetricUnit(result.metric);
|
||||
|
||||
qreal valuePerIteration = qreal(result.value) / qreal(result.iterations);
|
||||
char resultBuffer[100] = "";
|
||||
formatResult(resultBuffer, 100, valuePerIteration, countSignificantDigits(result.value));
|
||||
|
||||
char buf2[1024];
|
||||
QTest::qt_snprintf(
|
||||
buf2, sizeof(buf2), "%s %s",
|
||||
resultBuffer,
|
||||
unitText);
|
||||
|
||||
char buf2_[1024];
|
||||
QByteArray iterationText = " per iteration";
|
||||
Q_ASSERT(result.iterations > 0);
|
||||
QTest::qt_snprintf(
|
||||
buf2_,
|
||||
sizeof(buf2_), "%s",
|
||||
iterationText.data());
|
||||
|
||||
char buf3[1024];
|
||||
Q_ASSERT(result.iterations > 0);
|
||||
formatResult(resultBuffer, 100, result.value, countSignificantDigits(result.value));
|
||||
QTest::qt_snprintf(
|
||||
buf3, sizeof(buf3), " (total: %s, iterations: %d)",
|
||||
resultBuffer,
|
||||
result.iterations);
|
||||
|
||||
char buf[1024];
|
||||
|
||||
if (result.setByMacro) {
|
||||
QTest::qt_snprintf(
|
||||
buf, sizeof(buf), "%s%s%s%s%s%s\n", buf1, bufTag, fill, buf2, buf2_, buf3);
|
||||
} else {
|
||||
QTest::qt_snprintf(buf, sizeof(buf), "%s%s%s%s\n", buf1, bufTag, fill, buf2);
|
||||
}
|
||||
|
||||
memcpy(buf, bmtag, strlen(bmtag));
|
||||
outputMessage(buf);
|
||||
delete hbuffer;
|
||||
}
|
||||
else {
|
||||
// fast, no allocations, but truncates silently
|
||||
RDebug::RawPrint(format);
|
||||
TPtrC8 ptr(reinterpret_cast<const TUint8*>(str));
|
||||
RDebug::RawPrint(ptr);
|
||||
RDebug::RawPrint(_L8("\n"));
|
||||
}
|
||||
#endif
|
||||
outputString(str);
|
||||
}
|
||||
|
||||
void QPlainTestLogger::printMessage(const char *type, const char *msg, const char *file, int line)
|
||||
{
|
||||
QTEST_ASSERT(type);
|
||||
QTEST_ASSERT(msg);
|
||||
|
||||
QTestCharBuffer buf;
|
||||
|
||||
const char *fn = QTestResult::currentTestFunction() ? QTestResult::currentTestFunction()
|
||||
: "UnknownTestFunc";
|
||||
const char *tag = QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "";
|
||||
const char *gtag = QTestResult::currentGlobalDataTag()
|
||||
? QTestResult::currentGlobalDataTag()
|
||||
: "";
|
||||
const char *filler = (tag[0] && gtag[0]) ? ":" : "";
|
||||
if (file) {
|
||||
QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n"
|
||||
#ifdef Q_OS_WIN
|
||||
"%s(%d) : failure location\n"
|
||||
#else
|
||||
" Loc: [%s(%d)]\n"
|
||||
#endif
|
||||
, type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
|
||||
msg[0] ? " " : "", msg, file, line);
|
||||
} else {
|
||||
QTest::qt_asprintf(&buf, "%s: %s::%s(%s%s%s)%s%s\n",
|
||||
type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
|
||||
msg[0] ? " " : "", msg);
|
||||
}
|
||||
// In colored mode, printf above stripped our nonprintable control characters.
|
||||
// Put them back.
|
||||
memcpy(buf.data(), type, strlen(type));
|
||||
outputMessage(buf.data());
|
||||
}
|
||||
|
||||
//void QPlainTestLogger::printBenchmarkResult(const char *bmtag, int value, int iterations)
|
||||
void QPlainTestLogger::printBenchmarkResult(const QBenchmarkResult &result)
|
||||
{
|
||||
const char *bmtag = QTest::benchmarkResult2String();
|
||||
|
||||
char buf1[1024];
|
||||
QTest::qt_snprintf(
|
||||
buf1, sizeof(buf1), "%s: %s::%s",
|
||||
bmtag,
|
||||
QTestResult::currentTestObjectName(),
|
||||
result.context.slotName.toAscii().data());
|
||||
|
||||
char bufTag[1024];
|
||||
bufTag[0] = 0;
|
||||
QByteArray tag = result.context.tag.toAscii();
|
||||
if (tag.isEmpty() == false) {
|
||||
QTest::qt_snprintf(bufTag, sizeof(bufTag), ":\"%s\"", tag.data());
|
||||
}
|
||||
|
||||
|
||||
char fillFormat[8];
|
||||
int fillLength = 5;
|
||||
QTest::qt_snprintf(
|
||||
fillFormat, sizeof(fillFormat), ":\n%%%ds", fillLength);
|
||||
char fill[1024];
|
||||
QTest::qt_snprintf(fill, sizeof(fill), fillFormat, "");
|
||||
|
||||
const char * unitText = QTest::benchmarkMetricUnit(result.metric);
|
||||
|
||||
qreal valuePerIteration = qreal(result.value) / qreal(result.iterations);
|
||||
char resultBuffer[100] = "";
|
||||
QTest::formatResult(resultBuffer, 100, valuePerIteration, QTest::countSignificantDigits(result.value));
|
||||
|
||||
char buf2[1024];
|
||||
QTest::qt_snprintf(
|
||||
buf2, sizeof(buf2), "%s %s",
|
||||
resultBuffer,
|
||||
unitText);
|
||||
|
||||
char buf2_[1024];
|
||||
QByteArray iterationText = " per iteration";
|
||||
Q_ASSERT(result.iterations > 0);
|
||||
QTest::qt_snprintf(
|
||||
buf2_,
|
||||
sizeof(buf2_), "%s",
|
||||
iterationText.data());
|
||||
|
||||
char buf3[1024];
|
||||
Q_ASSERT(result.iterations > 0);
|
||||
QTest::formatResult(resultBuffer, 100, result.value, QTest::countSignificantDigits(result.value));
|
||||
QTest::qt_snprintf(
|
||||
buf3, sizeof(buf3), " (total: %s, iterations: %d)",
|
||||
resultBuffer,
|
||||
result.iterations);
|
||||
|
||||
char buf[1024];
|
||||
|
||||
if (result.setByMacro) {
|
||||
QTest::qt_snprintf(
|
||||
buf, sizeof(buf), "%s%s%s%s%s%s\n", buf1, bufTag, fill, buf2, buf2_, buf3);
|
||||
} else {
|
||||
QTest::qt_snprintf(buf, sizeof(buf), "%s%s%s%s\n", buf1, bufTag, fill, buf2);
|
||||
}
|
||||
|
||||
memcpy(buf, bmtag, strlen(bmtag));
|
||||
outputMessage(buf);
|
||||
}
|
||||
|
||||
QPlainTestLogger::QPlainTestLogger()
|
||||
@ -380,7 +380,7 @@ void QPlainTestLogger::startLogging(const char *filename)
|
||||
", Qt %s\n", QTestResult::currentTestObjectName(), qVersion());
|
||||
}
|
||||
}
|
||||
QTest::outputMessage(buf);
|
||||
outputMessage(buf);
|
||||
}
|
||||
|
||||
void QPlainTestLogger::stopLogging()
|
||||
@ -397,7 +397,7 @@ void QPlainTestLogger::stopLogging()
|
||||
QTestResult::passCount(), QTestResult::failCount(),
|
||||
QTestResult::skipCount(), QTestResult::currentTestObjectName());
|
||||
}
|
||||
QTest::outputMessage(buf);
|
||||
outputMessage(buf);
|
||||
|
||||
QAbstractTestLogger::stopLogging();
|
||||
}
|
||||
@ -406,7 +406,7 @@ void QPlainTestLogger::stopLogging()
|
||||
void QPlainTestLogger::enterTestFunction(const char * /*function*/)
|
||||
{
|
||||
if (QTestLog::verboseLevel() >= 1)
|
||||
QTest::printMessage(QTest::messageType2String(Info), "entering");
|
||||
printMessage(QTest::messageType2String(Info), "entering");
|
||||
}
|
||||
|
||||
void QPlainTestLogger::leaveTestFunction()
|
||||
@ -420,13 +420,13 @@ void QPlainTestLogger::addIncident(IncidentTypes type, const char *description,
|
||||
if (type == QAbstractTestLogger::Pass && QTestLog::verboseLevel() < 0)
|
||||
return;
|
||||
|
||||
QTest::printMessage(QTest::incidentType2String(type), description, file, line);
|
||||
printMessage(QTest::incidentType2String(type), description, file, line);
|
||||
}
|
||||
|
||||
void QPlainTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
|
||||
{
|
||||
// QTest::printBenchmarkResult(QTest::benchmarkResult2String(), value, iterations);
|
||||
QTest::printBenchmarkResult(result);
|
||||
// printBenchmarkResult(QTest::benchmarkResult2String(), value, iterations);
|
||||
printBenchmarkResult(result);
|
||||
}
|
||||
|
||||
void QPlainTestLogger::addMessage(MessageTypes type, const char *message,
|
||||
@ -437,7 +437,7 @@ void QPlainTestLogger::addMessage(MessageTypes type, const char *message,
|
||||
&& QTestLog::verboseLevel() < 0)
|
||||
return;
|
||||
|
||||
QTest::printMessage(QTest::messageType2String(type), message, file, line);
|
||||
printMessage(QTest::messageType2String(type), message, file, line);
|
||||
}
|
||||
|
||||
void QPlainTestLogger::registerRandomSeed(unsigned int seed)
|
||||
|
@ -79,6 +79,10 @@ public:
|
||||
private:
|
||||
unsigned int randomSeed;
|
||||
bool hasRandomSeed;
|
||||
|
||||
void printMessage(const char *type, const char *msg, const char *file = 0, int line = 0);
|
||||
void outputMessage(const char *str);
|
||||
void printBenchmarkResult(const QBenchmarkResult &result);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -154,12 +154,12 @@ void QTestBasicStreamer::outputString(const char *msg) const
|
||||
testLogger->outputString(msg);
|
||||
}
|
||||
|
||||
void QTestBasicStreamer::setLogger(const QTestLogger *tstLogger)
|
||||
void QTestBasicStreamer::setLogger(QTestLogger *tstLogger)
|
||||
{
|
||||
testLogger = tstLogger;
|
||||
}
|
||||
|
||||
const QTestLogger *QTestBasicStreamer::logger() const
|
||||
QTestLogger *QTestBasicStreamer::logger() const
|
||||
{
|
||||
return testLogger;
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ class QTestBasicStreamer
|
||||
|
||||
void outputString(const char *msg) const;
|
||||
|
||||
void setLogger(const QTestLogger *tstLogger);
|
||||
const QTestLogger *logger() const;
|
||||
void setLogger(QTestLogger *tstLogger);
|
||||
QTestLogger *logger() const;
|
||||
|
||||
protected:
|
||||
virtual void formatStart(const QTestElement *element, QTestCharBuffer *formatted) const;
|
||||
@ -78,7 +78,7 @@ class QTestBasicStreamer
|
||||
virtual void outputElementAttributes(const QTestElement *element, QTestElementAttribute *attribute) const;
|
||||
|
||||
private:
|
||||
const QTestLogger *testLogger;
|
||||
QTestLogger *testLogger;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
Loading…
Reference in New Issue
Block a user