diff options
Diffstat (limited to 'src/testlib')
-rw-r--r-- | src/testlib/qabstracttestlogger_p.h | 2 | ||||
-rw-r--r-- | src/testlib/qplaintestlogger.cpp | 4 | ||||
-rw-r--r-- | src/testlib/qplaintestlogger_p.h | 2 | ||||
-rw-r--r-- | src/testlib/qtestcase.cpp | 48 | ||||
-rw-r--r-- | src/testlib/qtestcase.h | 89 | ||||
-rw-r--r-- | src/testlib/qtestlog.cpp | 93 | ||||
-rw-r--r-- | src/testlib/qtestlog_p.h | 2 | ||||
-rw-r--r-- | src/testlib/qxmltestlogger.cpp | 22 | ||||
-rw-r--r-- | src/testlib/qxmltestlogger_p.h | 5 | ||||
-rw-r--r-- | src/testlib/qxunittestlogger.cpp | 8 | ||||
-rw-r--r-- | src/testlib/qxunittestlogger_p.h | 2 |
11 files changed, 218 insertions, 59 deletions
diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h index c471717655..c549233ddb 100644 --- a/src/testlib/qabstracttestlogger_p.h +++ b/src/testlib/qabstracttestlogger_p.h @@ -94,7 +94,7 @@ public: const char *file = 0, int line = 0) = 0; virtual void addBenchmarkResult(const QBenchmarkResult &result) = 0; - virtual void addMessage(MessageTypes type, const char *message, + virtual void addMessage(MessageTypes type, const QString &message, const char *file = 0, int line = 0) = 0; void outputString(const char *msg); diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp index 3f65dc0a6e..39580f22d4 100644 --- a/src/testlib/qplaintestlogger.cpp +++ b/src/testlib/qplaintestlogger.cpp @@ -389,14 +389,14 @@ void QPlainTestLogger::addBenchmarkResult(const QBenchmarkResult &result) printBenchmarkResult(result); } -void QPlainTestLogger::addMessage(MessageTypes type, const char *message, +void QPlainTestLogger::addMessage(MessageTypes type, const QString &message, const char *file, int line) { // suppress non-fatal messages in silent mode if (type != QAbstractTestLogger::QFatal && QTestLog::verboseLevel() < 0) return; - printMessage(QTest::messageType2String(type), message, file, line); + printMessage(QTest::messageType2String(type), qPrintable(message), file, line); } QT_END_NAMESPACE diff --git a/src/testlib/qplaintestlogger_p.h b/src/testlib/qplaintestlogger_p.h index 8aa0d745e9..69dbc89649 100644 --- a/src/testlib/qplaintestlogger_p.h +++ b/src/testlib/qplaintestlogger_p.h @@ -73,7 +73,7 @@ public: const char *file = 0, int line = 0); void addBenchmarkResult(const QBenchmarkResult &result); - void addMessage(MessageTypes type, const char *message, + void addMessage(MessageTypes type, const QString &message, const char *file = 0, int line = 0); private: diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e170d2a044..224357dd85 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -165,6 +165,25 @@ QT_BEGIN_NAMESPACE \sa QVERIFY(), QTRY_COMPARE(), QTest::toString() */ +/*! \macro QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) + \since 5.3 + + \relates QTest + + The QVERIFY_EXCEPTION_THROWN macro executes an \a expression and tries + to catch an exception thrown from the \a expression. If the \a expression + throws an exception and its type is the same as \a exceptiontype + or \a exceptiontype is substitutable with the type of thrown exception + (i.e. usually the type of thrown exception is publically derived + from \a exceptiontype) then execution will be continued. If not-substitutable + type of exception is thrown or the \a expression doesn't throw an exception + at all, then a failure will be recorded in the test log and + the test won't be executed further. + + \note This macro can only be used in a test function that is invoked + by the test framework. +*/ + /*! \macro QTRY_VERIFY_WITH_TIMEOUT(condition, timeout) \since 5.0 @@ -1540,6 +1559,10 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) } else if (strcmp(argv[i], "-vb") == 0) { QBenchmarkGlobalData::current->verboseOutput = true; +#ifdef Q_OS_WINRT + } else if (strncmp(argv[i], "-ServerName:", 12) == 0) { + continue; +#endif } else if (argv[i][0] == '-') { fprintf(stderr, "Unknown option: '%s'\n\n%s", argv[i], testOptions); if (qml) { @@ -2170,13 +2193,15 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) qtest_qParseArgs(argc, argv, false); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (!noCrashHandler) { # ifndef Q_CC_MINGW _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); # endif +# ifndef Q_OS_WINRT SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); SetUnhandledExceptionFilter(windowsFaultHandler); +# endif } // !noCrashHandler #endif // Q_OS_WIN) && !Q_OS_WINCE && !Q_OS_WINRT @@ -2325,6 +2350,27 @@ void QTest::ignoreMessage(QtMsgType type, const char *message) QTestLog::ignoreMessage(type, message); } +/*! + \overload + + Ignores messages created by qDebug() or qWarning(). If the \a message + matching \a messagePattern + with the corresponding \a type is outputted, it will be removed from the + test log. If the test finished and the \a message was not outputted, + a test failure is appended to the test log. + + \b {Note:} Invoking this function will only ignore one message. + If the message you want to ignore is outputted twice, you have to + call ignoreMessage() twice, too. + + \since 5.3 +*/ + +void QTest::ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern) +{ + QTestLog::ignoreMessage(type, messagePattern); +} + /*! \internal */ diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index ba727b5afe..05da33c400 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -51,8 +51,14 @@ #include <string.h> +#ifndef QT_NO_EXCEPTIONS +# include <exception> +#endif // QT_NO_EXCEPTIONS + + QT_BEGIN_NAMESPACE +class QRegularExpression; #define QVERIFY(statement) \ do {\ @@ -83,34 +89,84 @@ do {\ return;\ } while (0) -// Will try to wait for the expression to become true while allowing event processing -#define QTRY_VERIFY_WITH_TIMEOUT(__expr, __timeout) \ -do { \ - const int __step = 50; \ - const int __timeoutValue = __timeout; \ + +#ifndef QT_NO_EXCEPTIONS + +# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ + do {\ + QT_TRY {\ + QT_TRY {\ + expression;\ + QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ + " but no exception caught", __FILE__, __LINE__);\ + return;\ + } QT_CATCH (const exceptiontype &) {\ + }\ + } QT_CATCH (const std::exception &e) {\ + QByteArray msg = QByteArray() + "Expected exception of type " #exceptiontype \ + " to be thrown but std::exception caught with message: " + e.what(); \ + QTest::qFail(msg.constData(), __FILE__, __LINE__);\ + return;\ + } QT_CATCH (...) {\ + QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ + " but unknown exception caught", __FILE__, __LINE__);\ + return;\ + }\ + } while (0) + +#else // QT_NO_EXCEPTIONS + +/* + * The expression passed to the macro should throw an exception and we can't + * catch it because Qt has been compiled without exception support. We can't + * skip the expression because it may have side effects and must be executed. + * So, users must use Qt with exception support enabled if they use exceptions + * in their code. + */ +# define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ + Q_STATIC_ASSERT_X(false, "Support of exceptions is disabled") + +#endif // !QT_NO_EXCEPTIONS + + +#define QTRY_LOOP_IMPL(__expr, __timeoutValue, __step) \ if (!(__expr)) { \ QTest::qWait(0); \ } \ - for (int __i = 0; __i < __timeoutValue && !(__expr); __i+=__step) { \ + int __i = 0; \ + for (; __i < __timeoutValue && !(__expr); __i += __step) { \ QTest::qWait(__step); \ - } \ + } + +#define QTRY_TIMEOUT_DEBUG_IMPL(__expr, __timeoutValue, __step)\ + if (!(__expr)) { \ + QTRY_LOOP_IMPL(__expr, (2 * __timeoutValue), __step);\ + if (__expr) { \ + QString msg = QString::fromUtf8("QTestLib: This test case check (\"%1\") failed because the requested timeout (%2 ms) was too short, %3 ms would have been sufficient this time."); \ + msg = msg.arg(QString::fromUtf8(#__expr)).arg(__timeoutValue).arg(__timeoutValue + __i); \ + QFAIL(qPrintable(msg)); \ + } \ + } + +#define QTRY_IMPL(__expr, __timeout)\ + const int __step = 50; \ + const int __timeoutValue = __timeout; \ + QTRY_LOOP_IMPL(__expr, __timeoutValue, __step); \ + QTRY_TIMEOUT_DEBUG_IMPL(__expr, __timeoutValue, __step)\ + +// Will try to wait for the expression to become true while allowing event processing +#define QTRY_VERIFY_WITH_TIMEOUT(__expr, __timeout) \ +do { \ + QTRY_IMPL(__expr, __timeout);\ QVERIFY(__expr); \ } while (0) #define QTRY_VERIFY(__expr) QTRY_VERIFY_WITH_TIMEOUT(__expr, 5000) // Will try to wait for the comparison to become successful while allowing event processing - #define QTRY_COMPARE_WITH_TIMEOUT(__expr, __expected, __timeout) \ do { \ - const int __step = 50; \ - const int __timeoutValue = __timeout; \ - if ((__expr) != (__expected)) { \ - QTest::qWait(0); \ - } \ - for (int __i = 0; __i < __timeoutValue && ((__expr) != (__expected)); __i+=__step) { \ - QTest::qWait(__step); \ - } \ + QTRY_IMPL(((__expr) == (__expected)), __timeout);\ QCOMPARE(__expr, __expected); \ } while (0) @@ -191,6 +247,7 @@ namespace QTest const char *file, int line); Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = 0, int line = 0); Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message); + Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const QRegularExpression &messagePattern); Q_TESTLIB_EXPORT QString qFindTestData(const char* basepath, const char* file = 0, int line = 0, const char* builddir = 0); Q_TESTLIB_EXPORT QString qFindTestData(const QString& basepath, const char* file = 0, int line = 0, const char* builddir = 0); diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index bbca5b94e5..74947b3f3a 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -49,6 +49,8 @@ #include <QtTest/private/qxmltestlogger_p.h> #include <QtCore/qatomic.h> #include <QtCore/qbytearray.h> +#include <QtCore/QVariant> +#include <QtCore/QRegularExpression> #include <stdlib.h> #include <string.h> @@ -86,11 +88,8 @@ namespace QTest { struct IgnoreResultList { - inline IgnoreResultList(QtMsgType tp, const char *message) - : type(tp), next(0) - { msg = qstrdup(message); } - inline ~IgnoreResultList() - { delete [] msg; } + inline IgnoreResultList(QtMsgType tp, const QVariant &patternIn) + : type(tp), pattern(patternIn), next(0) {} static inline void clearList(IgnoreResultList *&list) { @@ -101,8 +100,43 @@ namespace QTest { } } + static void append(IgnoreResultList *&list, QtMsgType type, const QVariant &patternIn) + { + QTest::IgnoreResultList *item = new QTest::IgnoreResultList(type, patternIn); + + if (!list) { + list = item; + return; + } + IgnoreResultList *last = list; + for ( ; last->next; last = last->next) ; + last->next = item; + } + + static bool stringsMatch(const QString &expected, const QString &actual) + { + if (expected == actual) + return true; + + // ignore an optional whitespace at the end of str + // (the space was added automatically by ~QDebug() until Qt 5.3, + // so autotests still might expect it) + if (expected.endsWith(QLatin1Char(' '))) + return actual == expected.leftRef(expected.length() - 1); + + return false; + } + + inline bool matches(QtMsgType tp, const QString &message) const + { + return tp == type + && (pattern.type() == QVariant::String ? + stringsMatch(pattern.toString(), message) : + pattern.toRegularExpression().match(message).hasMatch()); + } + QtMsgType type; - char *msg; + QVariant pattern; IgnoreResultList *next; }; @@ -175,7 +209,7 @@ namespace QTest { FOREACH_LOGGER(logger->addBenchmarkResult(result)); } - static void addMessage(QAbstractTestLogger::MessageTypes type, const char *message, + static void addMessage(QAbstractTestLogger::MessageTypes type, const QString &message, const char *file = 0, int line = 0) { FOREACH_LOGGER(logger->addMessage(type, message, file, line)); @@ -208,12 +242,14 @@ namespace QTest { static QtMessageHandler oldMessageHandler; - static bool handleIgnoredMessage(QtMsgType type, const char *msg) + static bool handleIgnoredMessage(QtMsgType type, const QString &message) { + if (!ignoreResultList) + return false; IgnoreResultList *last = 0; IgnoreResultList *list = ignoreResultList; while (list) { - if (list->type == type && strcmp(msg, list->msg) == 0) { + if (list->matches(type, message)) { // remove the item from the list if (last) last->next = list->next; @@ -242,12 +278,11 @@ namespace QTest { QTEST_ASSERT(QTest::TestLoggers::loggerCount() != 0); } - QByteArray msg = message.toLocal8Bit(); - if (handleIgnoredMessage(type, msg)) + if (handleIgnoredMessage(type, message)) // the message is expected, so just swallow it. return; - msg = qMessageFormatString(type, context, message).toLocal8Bit(); + QString msg = qMessageFormatString(type, context, message); msg.chop(1); // remove trailing newline if (type != QtFatalMsg) { @@ -256,7 +291,7 @@ namespace QTest { if (!counter.deref()) { QTest::TestLoggers::addMessage(QAbstractTestLogger::QSystem, - "Maximum amount of warnings exceeded. Use -maxwarnings to override."); + QStringLiteral("Maximum amount of warnings exceeded. Use -maxwarnings to override.")); return; } } @@ -317,11 +352,15 @@ void QTestLog::leaveTestFunction() void QTestLog::printUnhandledIgnoreMessages() { - char msg[1024]; + QString message; QTest::IgnoreResultList *list = QTest::ignoreResultList; while (list) { - qsnprintf(msg, 1024, "Did not receive message: \"%s\"", list->msg); - QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, msg); + if (list->pattern.type() == QVariant::String) { + message = QStringLiteral("Did not receive message: \"") + list->pattern.toString() + QLatin1Char('"'); + } else { + message = QStringLiteral("Did not receive any message matching: \"") + list->pattern.toRegularExpression().pattern() + QLatin1Char('"'); + } + QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, message); list = list->next; } @@ -378,7 +417,7 @@ void QTestLog::addSkip(const char *msg, const char *file, int line) ++QTest::skips; - QTest::TestLoggers::addMessage(QAbstractTestLogger::Skip, msg, file, line); + QTest::TestLoggers::addMessage(QAbstractTestLogger::Skip, QString::fromUtf8(msg), file, line); } void QTestLog::addBenchmarkResult(const QBenchmarkResult &result) @@ -442,14 +481,14 @@ void QTestLog::warn(const char *msg, const char *file, int line) QTEST_ASSERT(msg); if (QTest::TestLoggers::loggerCount() > 0) - QTest::TestLoggers::addMessage(QAbstractTestLogger::Warn, msg, file, line); + QTest::TestLoggers::addMessage(QAbstractTestLogger::Warn, QString::fromUtf8(msg), file, line); } void QTestLog::info(const char *msg, const char *file, int line) { QTEST_ASSERT(msg); - QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, msg, file, line); + QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, QString::fromUtf8(msg), file, line); } void QTestLog::setVerboseLevel(int level) @@ -466,16 +505,14 @@ void QTestLog::ignoreMessage(QtMsgType type, const char *msg) { QTEST_ASSERT(msg); - QTest::IgnoreResultList *item = new QTest::IgnoreResultList(type, msg); + QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QString::fromLocal8Bit(msg)); +} - QTest::IgnoreResultList *list = QTest::ignoreResultList; - if (!list) { - QTest::ignoreResultList = item; - return; - } - while (list->next) - list = list->next; - list->next = item; +void QTestLog::ignoreMessage(QtMsgType type, const QRegularExpression &expression) +{ + QTEST_ASSERT(expression.isValid()); + + QTest::IgnoreResultList::append(QTest::ignoreResultList, type, QVariant(expression)); } void QTestLog::setMaxWarnings(int m) diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h index df3e2ab5d4..bd83870934 100644 --- a/src/testlib/qtestlog_p.h +++ b/src/testlib/qtestlog_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE class QBenchmarkResult; +class QRegularExpression; class Q_TESTLIB_EXPORT QTestLog { @@ -75,6 +76,7 @@ public: static void addBenchmarkResult(const QBenchmarkResult &result); static void ignoreMessage(QtMsgType type, const char *msg); + static void ignoreMessage(QtMsgType type, const QRegularExpression &expression); static int unhandledIgnoreMessages(); static void printUnhandledIgnoreMessages(); static void clearIgnoreMessages(); diff --git a/src/testlib/qxmltestlogger.cpp b/src/testlib/qxmltestlogger.cpp index 3f77f152b5..3fff753c5c 100644 --- a/src/testlib/qxmltestlogger.cpp +++ b/src/testlib/qxmltestlogger.cpp @@ -121,10 +121,16 @@ void QXmlTestLogger::startLogging() " <QTestVersion>" QTEST_VERSION_STR "</QTestVersion>\n" "</Environment>\n", qVersion()); outputString(buf.constData()); + m_totalTime.start(); } void QXmlTestLogger::stopLogging() { + QTestCharBuffer buf; + QTest::qt_asprintf(&buf, + "<Duration msecs=\"%f\"/>\n", + m_totalTime.nsecsElapsed() / 1000000.); + outputString(buf.constData()); if (xmlmode == QXmlTestLogger::Complete) { outputString("</TestCase>\n"); } @@ -139,11 +145,19 @@ void QXmlTestLogger::enterTestFunction(const char *function) xmlQuote("edFunction, function); QTest::qt_asprintf(&buf, "<TestFunction name=\"%s\">\n", quotedFunction.constData()); outputString(buf.constData()); + + m_functionTime.start(); } void QXmlTestLogger::leaveTestFunction() { - outputString("</TestFunction>\n"); + QTestCharBuffer buf; + QTest::qt_asprintf(&buf, + " <Duration msecs=\"%f\"/>\n" + "</TestFunction>\n", + m_functionTime.nsecsElapsed() / 1000000.); + + outputString(buf.constData()); } namespace QTest @@ -257,7 +271,7 @@ void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result) outputString(buf.constData()); } -void QXmlTestLogger::addMessage(MessageTypes type, const char *message, +void QXmlTestLogger::addMessage(MessageTypes type, const QString &message, const char *file, int line) { QTestCharBuffer buf; @@ -274,10 +288,10 @@ void QXmlTestLogger::addMessage(MessageTypes type, const char *message, xmlQuote("edFile, file); xmlCdata(&cdataGtag, gtag); xmlCdata(&cdataTag, tag); - xmlCdata(&cdataDescription, message); + xmlCdata(&cdataDescription, message.toUtf8().constData()); QTest::qt_asprintf(&buf, - QTest::messageFormatString(QTest::isEmpty(message), notag), + QTest::messageFormatString(message.isEmpty(), notag), QTest::xmlMessageType2String(type), quotedFile.constData(), line, cdataGtag.constData(), diff --git a/src/testlib/qxmltestlogger_p.h b/src/testlib/qxmltestlogger_p.h index ba0185a2b3..8ca15e47e2 100644 --- a/src/testlib/qxmltestlogger_p.h +++ b/src/testlib/qxmltestlogger_p.h @@ -55,6 +55,7 @@ #include <QtTest/private/qabstracttestlogger_p.h> +#include <QtCore/qelapsedtimer.h> QT_BEGIN_NAMESPACE @@ -76,7 +77,7 @@ public: const char *file = 0, int line = 0); void addBenchmarkResult(const QBenchmarkResult &result); - void addMessage(MessageTypes type, const char *message, + void addMessage(MessageTypes type, const QString &message, const char *file = 0, int line = 0); static int xmlCdata(QTestCharBuffer *dest, char const* src); @@ -86,6 +87,8 @@ public: private: XmlMode xmlmode; + QElapsedTimer m_functionTime; + QElapsedTimer m_totalTime; }; QT_END_NAMESPACE diff --git a/src/testlib/qxunittestlogger.cpp b/src/testlib/qxunittestlogger.cpp index 0a1a5fb6f9..a47f77ae49 100644 --- a/src/testlib/qxunittestlogger.cpp +++ b/src/testlib/qxunittestlogger.cpp @@ -220,7 +220,7 @@ void QXunitTestLogger::addIncident(IncidentTypes type, const char *description, have some information about the expected failure. */ if (type == QAbstractTestLogger::XFail) { - QXunitTestLogger::addMessage(QAbstractTestLogger::Info, description, file, line); + QXunitTestLogger::addMessage(QAbstractTestLogger::Info, QString::fromUtf8(description), file, line); } } @@ -263,7 +263,7 @@ void QXunitTestLogger::addTag(QTestElement* element) element->addAttribute(QTest::AI_Tag, buf.constData()); } -void QXunitTestLogger::addMessage(MessageTypes type, const char *message, const char *file, int line) +void QXunitTestLogger::addMessage(MessageTypes type, const QString &message, const char *file, int line) { QTestElement *errorElement = new QTestElement(QTest::LET_Error); const char *typeBuf = 0; @@ -296,7 +296,7 @@ void QXunitTestLogger::addMessage(MessageTypes type, const char *message, const } errorElement->addAttribute(QTest::AI_Type, typeBuf); - errorElement->addAttribute(QTest::AI_Description, message); + errorElement->addAttribute(QTest::AI_Description, message.toUtf8().constData()); addTag(errorElement); if (file) @@ -314,7 +314,7 @@ void QXunitTestLogger::addMessage(MessageTypes type, const char *message, const // Also add the message to the system error log (i.e. stderr), if one exists if (errorLogElement) { QTestElement *systemErrorElement = new QTestElement(QTest::LET_Error); - systemErrorElement->addAttribute(QTest::AI_Description, message); + systemErrorElement->addAttribute(QTest::AI_Description, message.toUtf8().constData()); errorLogElement->addLogElement(systemErrorElement); } } diff --git a/src/testlib/qxunittestlogger_p.h b/src/testlib/qxunittestlogger_p.h index 2c39fa952c..754462473a 100644 --- a/src/testlib/qxunittestlogger_p.h +++ b/src/testlib/qxunittestlogger_p.h @@ -77,7 +77,7 @@ class QXunitTestLogger : public QAbstractTestLogger void addBenchmarkResult(const QBenchmarkResult &result); void addTag(QTestElement* element); - void addMessage(MessageTypes type, const char *message, + void addMessage(MessageTypes type, const QString &message, const char *file = 0, int line = 0); private: |