summaryrefslogtreecommitdiffstats
path: root/src/testlib
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/testlib
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/testlib')
-rw-r--r--src/testlib/3rdparty/callgrind_p.h147
-rw-r--r--src/testlib/3rdparty/cycle_p.h513
-rw-r--r--src/testlib/3rdparty/valgrind_p.h3926
-rw-r--r--src/testlib/qabstracttestlogger.cpp166
-rw-r--r--src/testlib/qabstracttestlogger_p.h174
-rw-r--r--src/testlib/qasciikey.cpp505
-rw-r--r--src/testlib/qbenchmark.cpp308
-rw-r--r--src/testlib/qbenchmark.h100
-rw-r--r--src/testlib/qbenchmark_p.h200
-rw-r--r--src/testlib/qbenchmarkevent.cpp108
-rw-r--r--src/testlib/qbenchmarkevent_p.h80
-rw-r--r--src/testlib/qbenchmarkmeasurement.cpp139
-rw-r--r--src/testlib/qbenchmarkmeasurement_p.h114
-rw-r--r--src/testlib/qbenchmarkmetric.cpp115
-rw-r--r--src/testlib/qbenchmarkmetric.h71
-rw-r--r--src/testlib/qbenchmarkmetric_p.h63
-rw-r--r--src/testlib/qbenchmarkvalgrind.cpp273
-rw-r--r--src/testlib/qbenchmarkvalgrind_p.h93
-rw-r--r--src/testlib/qplaintestlogger.cpp497
-rw-r--r--src/testlib/qplaintestlogger_p.h86
-rw-r--r--src/testlib/qsignaldumper.cpp212
-rw-r--r--src/testlib/qsignaldumper_p.h74
-rw-r--r--src/testlib/qsignalspy.h148
-rw-r--r--src/testlib/qsignalspy.qdoc84
-rw-r--r--src/testlib/qtest.h283
-rw-r--r--src/testlib/qtest_global.h92
-rw-r--r--src/testlib/qtest_gui.h118
-rw-r--r--src/testlib/qtestaccessible.h165
-rw-r--r--src/testlib/qtestassert.h61
-rw-r--r--src/testlib/qtestbasicstreamer.cpp219
-rw-r--r--src/testlib/qtestbasicstreamer.h91
-rw-r--r--src/testlib/qtestcase.cpp2332
-rw-r--r--src/testlib/qtestcase.h375
-rw-r--r--src/testlib/qtestcoreelement.h172
-rw-r--r--src/testlib/qtestcorelist.h136
-rw-r--r--src/testlib/qtestdata.cpp122
-rw-r--r--src/testlib/qtestdata.h97
-rw-r--r--src/testlib/qtestelement.cpp88
-rw-r--r--src/testlib/qtestelement.h75
-rw-r--r--src/testlib/qtestelementattribute.cpp177
-rw-r--r--src/testlib/qtestelementattribute.h111
-rw-r--r--src/testlib/qtestevent.h221
-rw-r--r--src/testlib/qtestevent.qdoc177
-rw-r--r--src/testlib/qtesteventloop.h136
-rw-r--r--src/testlib/qtestfilelogger.cpp114
-rw-r--r--src/testlib/qtestfilelogger.h67
-rw-r--r--src/testlib/qtestkeyboard.h194
-rw-r--r--src/testlib/qtestlightxmlstreamer.cpp184
-rw-r--r--src/testlib/qtestlightxmlstreamer.h72
-rw-r--r--src/testlib/qtestlog.cpp393
-rw-r--r--src/testlib/qtestlog_p.h108
-rw-r--r--src/testlib/qtestlogger.cpp449
-rw-r--r--src/testlib/qtestlogger_p.h133
-rw-r--r--src/testlib/qtestmouse.h150
-rw-r--r--src/testlib/qtestresult.cpp352
-rw-r--r--src/testlib/qtestresult_p.h112
-rw-r--r--src/testlib/qtestspontaneevent.h118
-rw-r--r--src/testlib/qtestsystem.h95
-rw-r--r--src/testlib/qtesttable.cpp266
-rw-r--r--src/testlib/qtesttable_p.h93
-rw-r--r--src/testlib/qtesttouch.h153
-rw-r--r--src/testlib/qtestxmlstreamer.cpp227
-rw-r--r--src/testlib/qtestxmlstreamer.h72
-rw-r--r--src/testlib/qtestxunitstreamer.cpp209
-rw-r--r--src/testlib/qtestxunitstreamer.h77
-rw-r--r--src/testlib/qxmltestlogger.cpp459
-rw-r--r--src/testlib/qxmltestlogger_p.h97
-rw-r--r--src/testlib/testlib.pro89
68 files changed, 17727 insertions, 0 deletions
diff --git a/src/testlib/3rdparty/callgrind_p.h b/src/testlib/3rdparty/callgrind_p.h
new file mode 100644
index 0000000000..10d79318c4
--- /dev/null
+++ b/src/testlib/3rdparty/callgrind_p.h
@@ -0,0 +1,147 @@
+
+/*
+ ----------------------------------------------------------------
+
+ Notice that the following BSD-style license applies to this one
+ file (callgrind.h) only. The rest of Valgrind is licensed under the
+ terms of the GNU General Public License, version 2, unless
+ otherwise indicated. See the COPYING file in the source
+ distribution for details.
+
+ ----------------------------------------------------------------
+
+ This file is part of callgrind, a valgrind tool for cache simulation
+ and call tree tracing.
+
+ Copyright (C) 2003-2007 Josef Weidendorfer. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ----------------------------------------------------------------
+
+ Notice that the above BSD-style license applies to this one file
+ (vgprof.h) only. The entire rest of Valgrind is licensed under
+ the terms of the GNU General Public License, version 2. See the
+ COPYING file in the source distribution for details.
+
+ ----------------------------------------------------------------
+*/
+
+#ifndef __CALLGRIND_H
+#define __CALLGRIND_H
+
+#include "valgrind_p.h"
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
+ This enum comprises an ABI exported by Valgrind to programs
+ which use client requests. DO NOT CHANGE THE ORDER OF THESE
+ ENTRIES, NOR DELETE ANY -- add new ones at the end.
+
+ The identification ('C','T') for Callgrind has historical
+ reasons: it was called "Calltree" before. Besides, ('C','G') would
+ clash with cachegrind.
+ */
+
+typedef
+ enum {
+ VG_USERREQ__DUMP_STATS = VG_USERREQ_TOOL_BASE('C','T'),
+ VG_USERREQ__ZERO_STATS,
+ VG_USERREQ__TOGGLE_COLLECT,
+ VG_USERREQ__DUMP_STATS_AT,
+ VG_USERREQ__START_INSTRUMENTATION,
+ VG_USERREQ__STOP_INSTRUMENTATION
+ } Vg_CallgrindClientRequest;
+
+/* Dump current state of cost centers, and zero them afterwards */
+#define CALLGRIND_DUMP_STATS \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DUMP_STATS, \
+ 0, 0, 0, 0, 0); \
+ }
+
+/* Dump current state of cost centers, and zero them afterwards.
+ The argument is appended to a string stating the reason which triggered
+ the dump. This string is written as a description field into the
+ profile data dump. */
+#define CALLGRIND_DUMP_STATS_AT(pos_str) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DUMP_STATS_AT, \
+ pos_str, 0, 0, 0, 0); \
+ }
+
+/* Zero cost centers */
+#define CALLGRIND_ZERO_STATS \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__ZERO_STATS, \
+ 0, 0, 0, 0, 0); \
+ }
+
+/* Toggles collection state.
+ The collection state specifies whether the happening of events
+ should be noted or if they are to be ignored. Events are noted
+ by increment of counters in a cost center */
+#define CALLGRIND_TOGGLE_COLLECT \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__TOGGLE_COLLECT, \
+ 0, 0, 0, 0, 0); \
+ }
+
+/* Start full callgrind instrumentation if not already switched on.
+ When cache simulation is done, it will flush the simulated cache;
+ this will lead to an artifical cache warmup phase afterwards with
+ cache misses which would not have happened in reality. */
+#define CALLGRIND_START_INSTRUMENTATION \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__START_INSTRUMENTATION, \
+ 0, 0, 0, 0, 0); \
+ }
+
+/* Stop full callgrind instrumentation if not already switched off.
+ This flushes Valgrinds translation cache, and does no additional
+ instrumentation afterwards, which effectivly will run at the same
+ speed as the "none" tool (ie. at minimal slowdown).
+ Use this to bypass Callgrind aggregation for uninteresting code parts.
+ To start Callgrind in this mode to ignore the setup phase, use
+ the option "--instr-atstart=no". */
+#define CALLGRIND_STOP_INSTRUMENTATION \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STOP_INSTRUMENTATION, \
+ 0, 0, 0, 0, 0); \
+ }
+
+#endif /* __CALLGRIND_H */
diff --git a/src/testlib/3rdparty/cycle_p.h b/src/testlib/3rdparty/cycle_p.h
new file mode 100644
index 0000000000..a2924230ad
--- /dev/null
+++ b/src/testlib/3rdparty/cycle_p.h
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2003, 2006 Matteo Frigo
+ * Copyright (c) 2003, 2006 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* $Id: cycle.h,v 1.52 2006-02-08 02:36:47 athena Exp $ */
+
+/* machine-dependent cycle counters code. Needs to be inlined. */
+
+/***************************************************************************/
+/* To use the cycle counters in your code, simply #include "cycle.h" (this
+ file), and then use the functions/macros:
+
+ CycleCounterTicks getticks(void);
+
+ CycleCounterTicks is an opaque typedef defined below, representing the current time.
+ You extract the elapsed time between two calls to gettick() via:
+
+ double elapsed(CycleCounterTicks t1, CycleCounterTicks t0);
+
+ which returns a double-precision variable in arbitrary units. You
+ are not expected to convert this into human units like seconds; it
+ is intended only for *comparisons* of time intervals.
+
+ (In order to use some of the OS-dependent timer routines like
+ Solaris' gethrtime, you need to paste the autoconf snippet below
+ into your configure.ac file and #include "config.h" before cycle.h,
+ or define the relevant macros manually if you are not using autoconf.)
+*/
+
+/***************************************************************************/
+/* This file uses macros like HAVE_GETHRTIME that are assumed to be
+ defined according to whether the corresponding function/type/header
+ is available on your system. The necessary macros are most
+ conveniently defined if you are using GNU autoconf, via the tests:
+
+ dnl ---------------------------------------------------------------------
+
+ AC_C_INLINE
+ AC_HEADER_TIME
+ AC_CHECK_HEADERS([sys/time.h c_asm.h intrinsics.h mach/mach_time.h])
+
+ AC_CHECK_TYPE([hrtime_t],[AC_DEFINE(HAVE_HRTIME_T, 1, [Define to 1 if hrtime_t is defined in <sys/time.h>])],,[#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif])
+
+ AC_CHECK_FUNCS([gethrtime read_real_time time_base_to_time clock_gettime mach_absolute_time])
+
+ dnl Cray UNICOS _rtc() (real-time clock) intrinsic
+ AC_MSG_CHECKING([for _rtc intrinsic])
+ rtc_ok=yes
+ AC_TRY_LINK([#ifdef HAVE_INTRINSICS_H
+#include <intrinsics.h>
+#endif], [_rtc()], [AC_DEFINE(HAVE__RTC,1,[Define if you have the UNICOS _rtc() intrinsic.])], [rtc_ok=no])
+ AC_MSG_RESULT($rtc_ok)
+
+ dnl ---------------------------------------------------------------------
+*/
+
+/***************************************************************************/
+
+#ifndef QBENCHLIB_CYCLE_H
+#define QBENCHLIB_CYCLE_H
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#define INLINE_ELAPSED(INL) static INL double elapsed(CycleCounterTicks t1, CycleCounterTicks t0) \
+{ \
+ return (double)(t1 - t0); \
+}
+
+/*----------------------------------------------------------------*/
+/* Solaris */
+#if defined(HAVE_GETHRTIME) && defined(HAVE_HRTIME_T) && !defined(HAVE_TICK_COUNTER)
+typedef hrtime_t CycleCounterTicks;
+
+#define getticks gethrtime
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* AIX v. 4+ routines to read the real-time clock or time-base register */
+#if defined(HAVE_READ_REAL_TIME) && defined(HAVE_TIME_BASE_TO_TIME) && !defined(HAVE_TICK_COUNTER)
+typedef timebasestruct_t CycleCounterTicks;
+
+static inline CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks t;
+ read_real_time(&t, TIMEBASE_SZ);
+ return t;
+}
+
+static inline double elapsed(CycleCounterTicks t1, CycleCounterTicks t0) /* time in nanoseconds */
+{
+ time_base_to_time(&t1, TIMEBASE_SZ);
+ time_base_to_time(&t0, TIMEBASE_SZ);
+ return ((t1.tb_high - t0.tb_high) * 1e9 + (t1.tb_low - t0.tb_low));
+}
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * PowerPC ``cycle'' counter using the time base register.
+ */
+#if ((defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))) || (defined(__MWERKS__) && defined(macintosh))) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long CycleCounterTicks;
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ unsigned int tbl, tbu0, tbu1;
+
+ do {
+ __asm__ __volatile__ ("mftbu %0" : "=r"(tbu0));
+ __asm__ __volatile__ ("mftb %0" : "=r"(tbl));
+ __asm__ __volatile__ ("mftbu %0" : "=r"(tbu1));
+ } while (tbu0 != tbu1);
+
+ return (((unsigned long long)tbu0) << 32) | tbl;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* MacOS/Mach (Darwin) time-base register interface (unlike UpTime,
+ from Carbon, requires no additional libraries to be linked). */
+#if defined(HAVE_MACH_ABSOLUTE_TIME) && defined(HAVE_MACH_MACH_TIME_H) && !defined(HAVE_TICK_COUNTER)
+#include <mach/mach_time.h>
+typedef uint64_t CycleCounterTicks;
+#define getticks mach_absolute_time
+INLINE_ELAPSED(__inline__)
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * Pentium cycle counter
+ */
+#if (defined(__GNUC__) || defined(__ICC)) && defined(__i386__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long CycleCounterTicks;
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks ret;
+
+ __asm__ __volatile__("rdtsc": "=A" (ret));
+ /* no input, nothing else clobbered */
+ return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0 /* unreliable pentium IV cycle counter */
+#endif
+
+/* Visual C++ -- thanks to Morten Nissov for his help with this */
+#if defined(_MSC_VER)
+#if _MSC_VER >= 1200 && (_M_IX86 >= 500 || (defined(_WIN32_WCE) && defined(_X86_))) && !defined(HAVE_TICK_COUNTER)
+#include <windows.h>
+typedef LARGE_INTEGER CycleCounterTicks;
+#define RDTSC __asm __emit 0fh __asm __emit 031h /* hack for VC++ 5.0 */
+
+static __inline CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks retval;
+
+ __asm {
+ RDTSC
+ mov retval.HighPart, edx
+ mov retval.LowPart, eax
+ }
+ return retval;
+}
+
+static __inline double elapsed(CycleCounterTicks t1, CycleCounterTicks t0)
+{
+ return (double)(t1.QuadPart - t0.QuadPart);
+}
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0 /* unreliable pentium IV cycle counter */
+#endif
+#endif
+
+#if _MSC_VER >= 1400 && defined(_WIN32_WCE) && !defined(HAVE_TICK_COUNTER)
+#include <windows.h>
+typedef DWORD CycleCounterTicks;
+
+static __inline CycleCounterTicks getticks(void)
+{
+ return GetTickCount();
+}
+
+static __inline double elapsed(CycleCounterTicks t1, CycleCounterTicks t0)
+{
+ return (double)(t1 - t0);
+}
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * X86-64 cycle counter
+ */
+#if (defined(__GNUC__) || defined(__ICC)) && defined(__x86_64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long CycleCounterTicks;
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ unsigned a, d;
+ asm volatile("rdtsc" : "=a" (a), "=d" (d));
+ return ((CycleCounterTicks)a) | (((CycleCounterTicks)d) << 32);
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* PGI compiler, courtesy Cristiano Calonaci, Andrea Tarsi, & Roberto Gori.
+ NOTE: this code will fail to link unless you use the -Masmkeyword compiler
+ option (grrr). */
+#if defined(__PGI) && defined(__x86_64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long CycleCounterTicks;
+static CycleCounterTicks getticks(void)
+{
+ asm(" rdtsc; shl $0x20,%rdx; mov %eax,%eax; or %rdx,%rax; ");
+}
+INLINE_ELAPSED(__inline__)
+#define HAVE_TICK_COUNTER
+#endif
+
+/* Visual C++ */
+#if _MSC_VER >= 1400 && (defined(_M_AMD64) || defined(_M_X64)) && !defined(HAVE_TICK_COUNTER)
+#include <intrin.h>
+
+typedef unsigned __int64 CycleCounterTicks;
+
+#define getticks __rdtsc
+
+INLINE_ELAPSED(__inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * IA64 cycle counter
+ */
+
+/* intel's icc/ecc compiler */
+#if (defined(__EDG_VERSION) || defined(__ECC)) && defined(__ia64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long CycleCounterTicks;
+#include <ia64intrin.h>
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ return __getReg(_IA64_REG_AR_ITC);
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* gcc */
+#if defined(__GNUC__) && defined(__ia64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long CycleCounterTicks;
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks ret;
+
+ __asm__ __volatile__ ("mov %0=ar.itc" : "=r"(ret));
+ return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* HP/UX IA64 compiler, courtesy Teresa L. Johnson: */
+#if defined(__hpux) && defined(__ia64) && !defined(HAVE_TICK_COUNTER)
+#include <machine/sys/inline.h>
+typedef unsigned long CycleCounterTicks;
+
+static inline CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks ret;
+
+ ret = _Asm_mov_from_ar (_AREG_ITC);
+ return ret;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* Microsoft Visual C++ */
+#if defined(_MSC_VER) && defined(_M_IA64) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned __int64 CycleCounterTicks;
+
+# ifdef __cplusplus
+extern "C"
+# endif
+ticks __getReg(int whichReg);
+#pragma intrinsic(__getReg)
+
+static __inline CycleCounterTicks getticks(void)
+{
+ volatile CycleCounterTicks temp;
+ temp = __getReg(3116);
+ return temp;
+}
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * PA-RISC cycle counter
+ */
+#if (defined(__hppa__) || defined(__hppa)) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long CycleCounterTicks;
+
+# ifdef __GNUC__
+static __inline__ CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks ret;
+
+ __asm__ __volatile__("mfctl 16, %0": "=r" (ret));
+ /* no input, nothing else clobbered */
+ return ret;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+
+# elif 0 // Doesn't compile
+# include <machine/inline.h>
+static inline unsigned long getticks(void)
+{
+ register CycleCounterTicks ret;
+ _MFCTL(16, ret);
+ return ret;
+}
+# endif
+
+#endif
+
+/*----------------------------------------------------------------*/
+/* S390, courtesy of James Treacy */
+#if defined(__GNUC__) && defined(__s390__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long CycleCounterTicks;
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks cycles;
+ __asm__("stck 0(%0)" : : "a" (&(cycles)) : "memory", "cc");
+ return cycles;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+/*----------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__alpha__) && !defined(HAVE_TICK_COUNTER)
+/*
+ * The 32-bit cycle counter on alpha overflows pretty quickly,
+ * unfortunately. A 1GHz machine overflows in 4 seconds.
+ */
+typedef unsigned int CycleCounterTicks;
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ unsigned long cc;
+ __asm__ __volatile__ ("rpcc %0" : "=r"(cc));
+ return (cc & 0xFFFFFFFF);
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__sparc_v9__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long CycleCounterTicks;
+
+static __inline__ CycleCounterTicks getticks(void)
+{
+ CycleCounterTicks ret;
+ __asm__ __volatile__("rd %%tick, %0" : "=r" (ret));
+ return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+#if (defined(__DECC) || defined(__DECCXX)) && defined(__alpha) && defined(HAVE_C_ASM_H) && !defined(HAVE_TICK_COUNTER)
+# include <c_asm.h>
+typedef unsigned int CycleCounterTicks;
+
+static __inline CycleCounterTicks getticks(void)
+{
+ unsigned long cc;
+ cc = asm("rpcc %v0");
+ return (cc & 0xFFFFFFFF);
+}
+
+INLINE_ELAPSED(__inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+/*----------------------------------------------------------------*/
+/* SGI/Irix */
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE) && !defined(HAVE_TICK_COUNTER)
+typedef struct timespec CycleCounterTicks;
+
+static inline CycleCounterTicks getticks(void)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_SGI_CYCLE, &t);
+ return t;
+}
+
+static inline double elapsed(CycleCounterTicks t1, CycleCounterTicks t0)
+{
+ return (double)(t1.tv_sec - t0.tv_sec) * 1.0E9 +
+ (double)(t1.tv_nsec - t0.tv_nsec);
+}
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* Cray UNICOS _rtc() intrinsic function */
+#if defined(HAVE__RTC) && !defined(HAVE_TICK_COUNTER)
+#ifdef HAVE_INTRINSICS_H
+# include <intrinsics.h>
+#endif
+
+typedef long long CycleCounterTicks;
+
+#define getticks _rtc
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* Symbian */
+#if defined(__SYMBIAN32__) && !defined(HAVE_TICK_COUNTER)
+#include <e32std.h>
+
+typedef TUint32 CycleCounterTicks;
+
+static inline CycleCounterTicks getticks(void)
+{
+ return User::FastCounter();
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+#endif // QBENCHLIB_CYCLE_H
diff --git a/src/testlib/3rdparty/valgrind_p.h b/src/testlib/3rdparty/valgrind_p.h
new file mode 100644
index 0000000000..6380a9f28d
--- /dev/null
+++ b/src/testlib/3rdparty/valgrind_p.h
@@ -0,0 +1,3926 @@
+/* -*- c -*-
+ ----------------------------------------------------------------
+
+ Notice that the following BSD-style license applies to this one
+ file (valgrind.h) only. The rest of Valgrind is licensed under the
+ terms of the GNU General Public License, version 2, unless
+ otherwise indicated. See the COPYING file in the source
+ distribution for details.
+
+ ----------------------------------------------------------------
+
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2007 Julian Seward. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ----------------------------------------------------------------
+
+ Notice that the above BSD-style license applies to this one file
+ (valgrind.h) only. The entire rest of Valgrind is licensed under
+ the terms of the GNU General Public License, version 2. See the
+ COPYING file in the source distribution for details.
+
+ ----------------------------------------------------------------
+*/
+
+
+/* This file is for inclusion into client (your!) code.
+
+ You can use these macros to manipulate and query Valgrind's
+ execution inside your own programs.
+
+ The resulting executables will still run without Valgrind, just a
+ little bit more slowly than they otherwise would, but otherwise
+ unchanged. When not running on valgrind, each client request
+ consumes very few (eg. 7) instructions, so the resulting performance
+ loss is negligible unless you plan to execute client requests
+ millions of times per second. Nevertheless, if that is still a
+ problem, you can compile with the NVALGRIND symbol defined (gcc
+ -DNVALGRIND) so that client requests are not even compiled in. */
+
+#ifndef __VALGRIND_H
+#define __VALGRIND_H
+
+#include <stdarg.h>
+
+/* Nb: this file might be included in a file compiled with -ansi. So
+ we can't use C++ style "//" comments nor the "asm" keyword (instead
+ use "__asm__"). */
+
+/* Derive some tags indicating what the target platform is. Note
+ that in this file we're using the compiler's CPP symbols for
+ identifying architectures, which are different to the ones we use
+ within the rest of Valgrind. Note, __powerpc__ is active for both
+ 32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+ latter (on Linux, that is). */
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_ppc32_aix5
+#undef PLAT_ppc64_aix5
+
+#if !defined(_AIX) && defined(__i386__)
+# define PLAT_x86_linux 1
+#elif !defined(_AIX) && defined(__x86_64__)
+# define PLAT_amd64_linux 1
+#elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__)
+# define PLAT_ppc32_linux 1
+#elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__)
+# define PLAT_ppc64_linux 1
+#elif defined(_AIX) && defined(__64BIT__)
+# define PLAT_ppc64_aix5 1
+#elif defined(_AIX) && !defined(__64BIT__)
+# define PLAT_ppc32_aix5 1
+#endif
+
+
+/* If we're not compiling for our target platform, don't generate
+ any inline asms. */
+#if !defined(PLAT_x86_linux) && !defined(PLAT_amd64_linux) \
+ && !defined(PLAT_ppc32_linux) && !defined(PLAT_ppc64_linux) \
+ && !defined(PLAT_ppc32_aix5) && !defined(PLAT_ppc64_aix5)
+# if !defined(NVALGRIND)
+# define NVALGRIND 1
+# endif
+#endif
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */
+/* in here of use to end-users -- skip to the next section. */
+/* ------------------------------------------------------------------ */
+
+#if defined(NVALGRIND)
+
+/* Define NVALGRIND to completely remove the Valgrind magic sequence
+ from the compiled code (analogous to NDEBUG's effects on
+ assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ { \
+ (_zzq_rlval) = (_zzq_default); \
+ }
+
+#else /* ! NVALGRIND */
+
+/* The following defines the magic code sequences which the JITter
+ spots and handles magically. Don't look too closely at them as
+ they will rot your brain.
+
+ The assembly code sequences for all architectures is in this one
+ file. This is because this file must be stand-alone, and we don't
+ want to have multiple files.
+
+ For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+ value gets put in the return slot, so that everything works when
+ this is executed not under Valgrind. Args are passed in a memory
+ block, and so there's no intrinsic limit to the number that could
+ be passed, but it's currently five.
+
+ The macro args are:
+ _zzq_rlval result lvalue
+ _zzq_default default value (result returned when running on real CPU)
+ _zzq_request request code
+ _zzq_arg1..5 request params
+
+ The other two macros are used to support function wrapping, and are
+ a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the
+ guest's NRADDR pseudo-register and whatever other information is
+ needed to safely run the call original from the wrapper: on
+ ppc64-linux, the R2 value at the divert point is also needed. This
+ information is abstracted into a user-visible type, OrigFn.
+
+ VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
+ guest, but guarantees that the branch instruction will not be
+ redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
+ branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a
+ complete inline asm, since it needs to be combined with more magic
+ inline asm stuff to be useful.
+*/
+
+/* ------------------------- x86-linux ------------------------- */
+
+#if defined(PLAT_x86_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "roll $3, %%edi ; roll $13, %%edi\n\t" \
+ "roll $29, %%edi ; roll $19, %%edi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ { volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EDX = client_request ( %EAX ) */ \
+ "xchgl %%ebx,%%ebx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EAX = guest_NRADDR */ \
+ "xchgl %%ecx,%%ecx" \
+ : "=a" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_EAX \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir *%EAX */ \
+ "xchgl %%edx,%%edx\n\t"
+#endif /* PLAT_x86_linux */
+
+/* ------------------------ amd64-linux ------------------------ */
+
+#if defined(PLAT_amd64_linux)
+
+typedef
+ struct {
+ unsigned long long int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \
+ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ { volatile unsigned long long int _zzq_args[6]; \
+ volatile unsigned long long int _zzq_result; \
+ _zzq_args[0] = (unsigned long long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %RDX = client_request ( %RAX ) */ \
+ "xchgq %%rbx,%%rbx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned long long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %RAX = guest_NRADDR */ \
+ "xchgq %%rcx,%%rcx" \
+ : "=a" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_RAX \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir *%RAX */ \
+ "xchgq %%rdx,%%rdx\n\t"
+#endif /* PLAT_amd64_linux */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \
+ "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned int _zzq_args[6]; \
+ unsigned int _zzq_result; \
+ unsigned int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 3,%1\n\t" /*default*/ \
+ "mr 4,%2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" /*result*/ \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_default), "b" (_zzq_ptr) \
+ : "cc", "memory", "r3", "r4"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+typedef
+ struct {
+ unsigned long long int nraddr; /* where's the code? */
+ unsigned long long int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
+ "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned long long int _zzq_args[6]; \
+ register unsigned long long int _zzq_result __asm__("r3"); \
+ register unsigned long long int* _zzq_ptr __asm__("r4"); \
+ _zzq_args[0] = (unsigned long long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1" \
+ : "=r" (_zzq_result) \
+ : "0" (_zzq_default), "r" (_zzq_ptr) \
+ : "cc", "memory"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ register unsigned long long int __addr __asm__("r3"); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2" \
+ : "=r" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4" \
+ : "=r" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ unsigned int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \
+ "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned int _zzq_args[7]; \
+ register unsigned int _zzq_result; \
+ register unsigned int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ _zzq_args[6] = (unsigned int)(_zzq_default); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 4,%1\n\t" \
+ "lwz 3, 24(4)\n\t" \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_ptr) \
+ : "r3", "r4", "cc", "memory"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ register unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+typedef
+ struct {
+ unsigned long long int nraddr; /* where's the code? */
+ unsigned long long int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
+ "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned long long int _zzq_args[7]; \
+ register unsigned long long int _zzq_result; \
+ register unsigned long long int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned int long long)(_zzq_request); \
+ _zzq_args[1] = (unsigned int long long)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int long long)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int long long)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int long long)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int long long)(_zzq_arg5); \
+ _zzq_args[6] = (unsigned int long long)(_zzq_default); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 4,%1\n\t" \
+ "ld 3, 48(4)\n\t" \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_ptr) \
+ : "r3", "r4", "cc", "memory"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ register unsigned long long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_aix5 */
+
+/* Insert assembly code for other platforms here... */
+
+#endif /* NVALGRIND */
+
+
+/* ------------------------------------------------------------------ */
+/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */
+/* ugly. It's the least-worst tradeoff I can think of. */
+/* ------------------------------------------------------------------ */
+
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+ guaranteed-no-redirection macros, so as to get from function
+ wrappers to the functions they are wrapping. The whole point is to
+ construct standard call sequences, but to do the call itself with a
+ special no-redirect call pseudo-instruction that the JIT
+ understands and handles specially. This section is long and
+ repetitious, and I can't see a way to make it shorter.
+
+ The naming scheme is as follows:
+
+ CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc}
+
+ 'W' stands for "word" and 'v' for "void". Hence there are
+ different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+ and for each, the possibility of returning a word-typed result, or
+ no result.
+*/
+
+/* Use these to write the name of your wrapper. NOTE: duplicates
+ VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \
+ _vgwZU_##soname##_##fnname
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \
+ _vgwZZ_##soname##_##fnname
+
+/* Use this macro from within a wrapper function to collect the
+ context (address and possibly other info) of the original function.
+ Once you have that you can then use it in one of the CALL_FN_
+ macros. The type of the argument _lval is OrigFn. */
+#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval)
+
+/* Derivatives of the main macros below, for calling functions
+ returning void. */
+
+#define CALL_FN_v_v(fnptr) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_v_W(fnptr, arg1) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
+
+#define CALL_FN_v_WW(fnptr, arg1,arg2) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
+
+#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
+
+/* ------------------------- x86-linux ------------------------- */
+
+#if defined(PLAT_x86_linux)
+
+/* These regs are trashed by the hidden call. No need to mention eax
+ as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $4, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $8, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $12, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $16, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $20, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $24, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $28, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $32, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $36, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $40, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ "pushl 44(%%eax)\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $44, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ "pushl 48(%%eax)\n\t" \
+ "pushl 44(%%eax)\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $48, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_x86_linux */
+
+/* ------------------------ amd64-linux ------------------------ */
+
+#if defined(PLAT_amd64_linux)
+
+/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \
+ "rdi", "r8", "r9", "r10", "r11"
+
+/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
+ long) == 8. */
+
+/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_
+ macros. In order not to trash the stack redzone, we need to drop
+ %rsp by 128 before the hidden call, and restore afterwards. The
+ nastyness is that it is only by luck that the stack still appears
+ to be unwindable during the hidden call - since then the behaviour
+ of any routine using this macro does not match what the CFI data
+ says. Sigh.
+
+ Why is this important? Imagine that a wrapper has a stack
+ allocated local, and passes to the hidden call, a pointer to it.
+ Because gcc does not know about the hidden call, it may allocate
+ that local in the redzone. Unfortunately the hidden call may then
+ trash it before it comes to use it. So we must step clear of the
+ redzone, for the duration of the hidden call, to make it safe.
+
+ Probably the same problem afflicts the other redzone-style ABIs too
+ (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is
+ self describing (none of this CFI nonsense) so at least messing
+ with the stack pointer doesn't give a danger of non-unwindable
+ stack. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CALL_NOREDIR_RAX \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $8, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $16, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $24, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $32, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "pushq 88(%%rax)\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $40, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ "subq $128,%%rsp\n\t" \
+ "pushq 96(%%rax)\n\t" \
+ "pushq 88(%%rax)\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $48, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_amd64_linux */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+/* This is useful for finding out about the on-stack stuff:
+
+ extern int f9 ( int,int,int,int,int,int,int,int,int );
+ extern int f10 ( int,int,int,int,int,int,int,int,int,int );
+ extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
+ extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int );
+
+ int g9 ( void ) {
+ return f9(11,22,33,44,55,66,77,88,99);
+ }
+ int g10 ( void ) {
+ return f10(11,22,33,44,55,66,77,88,99,110);
+ }
+ int g11 ( void ) {
+ return f11(11,22,33,44,55,66,77,88,99,110,121);
+ }
+ int g12 ( void ) {
+ return f12(11,22,33,44,55,66,77,88,99,110,121,132);
+ }
+*/
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc32-linux,
+ sizeof(unsigned long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-16\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,16\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-16\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,16\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-32\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,16(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,32\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ _argvec[12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-32\n\t" \
+ /* arg12 */ \
+ "lwz 3,48(11)\n\t" \
+ "stw 3,20(1)\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,16(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,32\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+ long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,128" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,128" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,144" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg12 */ \
+ "ld 3,96(11)\n\t" \
+ "std 3,136(1)\n\t" \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,144" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+ still works. Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \
+ "addi 1,1,-" #_n_fr "\n\t" \
+ "lwz 3," #_n_fr "(1)\n\t" \
+ "stw 3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr) \
+ "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(64) \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(64) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(64) \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,60(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(64) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(72) \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,64(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,60(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(72) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(72) \
+ /* arg12 */ \
+ "lwz 3,48(11)\n\t" \
+ "stw 3,68(1)\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,64(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,60(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(72) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+ still works. Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \
+ "addi 1,1,-" #_n_fr "\n\t" \
+ "ld 3," #_n_fr "(1)\n\t" \
+ "std 3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr) \
+ "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned
+ long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(128) \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(128) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(128) \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(128) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(144) \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(144) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(144) \
+ /* arg12 */ \
+ "ld 3,96(11)\n\t" \
+ "std 3,136(1)\n\t" \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(144) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc64_aix5 */
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */
+/* */
+/* ------------------------------------------------------------------ */
+
+/* Some request codes. There are many more of these, but most are not
+ exposed to end-user view. These are the public ones, all of the
+ form 0x1000 + small_number.
+
+ Core ones are in the range 0x00000000--0x0000ffff. The non-public
+ ones start at 0x2000.
+*/
+
+/* These macros are used by tools -- they must be public, but don't
+ embed them into other programs. */
+#define VG_USERREQ_TOOL_BASE(a,b) \
+ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
+#define VG_IS_TOOL_USERREQ(a, b, v) \
+ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
+ This enum comprises an ABI exported by Valgrind to programs
+ which use client requests. DO NOT CHANGE THE ORDER OF THESE
+ ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+ enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001,
+ VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
+
+ /* These allow any function to be called from the simulated
+ CPU but run on the real CPU. Nb: the first arg passed to
+ the function is always the ThreadId of the running
+ thread! So CLIENT_CALL0 actually requires a 1 arg
+ function, etc. */
+ VG_USERREQ__CLIENT_CALL0 = 0x1101,
+ VG_USERREQ__CLIENT_CALL1 = 0x1102,
+ VG_USERREQ__CLIENT_CALL2 = 0x1103,
+ VG_USERREQ__CLIENT_CALL3 = 0x1104,
+
+ /* Can be useful in regression testing suites -- eg. can
+ send Valgrind's output to /dev/null and still count
+ errors. */
+ VG_USERREQ__COUNT_ERRORS = 0x1201,
+
+ /* These are useful and can be interpreted by any tool that
+ tracks malloc() et al, by using vg_replace_malloc.c. */
+ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
+ VG_USERREQ__FREELIKE_BLOCK = 0x1302,
+ /* Memory pool support. */
+ VG_USERREQ__CREATE_MEMPOOL = 0x1303,
+ VG_USERREQ__DESTROY_MEMPOOL = 0x1304,
+ VG_USERREQ__MEMPOOL_ALLOC = 0x1305,
+ VG_USERREQ__MEMPOOL_FREE = 0x1306,
+ VG_USERREQ__MEMPOOL_TRIM = 0x1307,
+ VG_USERREQ__MOVE_MEMPOOL = 0x1308,
+ VG_USERREQ__MEMPOOL_CHANGE = 0x1309,
+ VG_USERREQ__MEMPOOL_EXISTS = 0x130a,
+
+ /* Allow printfs to valgrind log. */
+ VG_USERREQ__PRINTF = 0x1401,
+ VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
+
+ /* Stack support. */
+ VG_USERREQ__STACK_REGISTER = 0x1501,
+ VG_USERREQ__STACK_DEREGISTER = 0x1502,
+ VG_USERREQ__STACK_CHANGE = 0x1503
+ } Vg_ClientRequest;
+
+#if !defined(__GNUC__)
+# define __extension__ /* */
+#endif
+
+/* Returns the number of Valgrinds this code is running under. That
+ is, 0 if running natively, 1 if running under Valgrind, 2 if
+ running under Valgrind which is running under another Valgrind,
+ etc. */
+#define RUNNING_ON_VALGRIND __extension__ \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */, \
+ VG_USERREQ__RUNNING_ON_VALGRIND, \
+ 0, 0, 0, 0, 0); \
+ _qzz_res; \
+ })
+
+
+/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
+ _qzz_len - 1]. Useful if you are debugging a JITter or some such,
+ since it provides a way to make sure valgrind will retranslate the
+ invalidated area. Returns no value. */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DISCARD_TRANSLATIONS, \
+ _qzz_addr, _qzz_len, 0, 0, 0); \
+ }
+
+
+/* These requests are for getting Valgrind itself to print something.
+ Possibly with a backtrace. This is a really ugly hack. */
+
+#if defined(NVALGRIND)
+
+# define VALGRIND_PRINTF(...)
+# define VALGRIND_PRINTF_BACKTRACE(...)
+
+#else /* NVALGRIND */
+
+/* Modern GCC will optimize the static routine out if unused,
+ and unused attribute will shut down warnings about it. */
+static int VALGRIND_PRINTF(const char *format, ...)
+ __attribute__((format(__printf__, 1, 2), __unused__));
+static int
+VALGRIND_PRINTF(const char *format, ...)
+{
+ unsigned long _qzz_res;
+ va_list vargs;
+ va_start(vargs, format);
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF,
+ (unsigned long)format, (unsigned long)vargs,
+ 0, 0, 0);
+ va_end(vargs);
+ return (int)_qzz_res;
+}
+
+static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+ __attribute__((format(__printf__, 1, 2), __unused__));
+static int
+VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+{
+ unsigned long _qzz_res;
+ va_list vargs;
+ va_start(vargs, format);
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE,
+ (unsigned long)format, (unsigned long)vargs,
+ 0, 0, 0);
+ va_end(vargs);
+ return (int)_qzz_res;
+}
+
+#endif /* NVALGRIND */
+
+
+/* These requests allow control to move from the simulated CPU to the
+ real CPU, calling an arbitary function.
+
+ Note that the current ThreadId is inserted as the first argument.
+ So this call:
+
+ VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
+
+ requires f to have this signature:
+
+ Word f(Word tid, Word arg1, Word arg2)
+
+ where "Word" is a word-sized type.
+
+ Note that these client requests are not entirely reliable. For example,
+ if you call a function with them that subsequently calls printf(),
+ there's a high chance Valgrind will crash. Generally, your prospects of
+ these working are made higher if the called function does not refer to
+ any global variables, and does not refer to any libc or other functions
+ (printf et al). Any kind of entanglement with libc or dynamic linking is
+ likely to have a bad outcome, for tricky reasons which we've grappled
+ with a lot in the past.
+*/
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL0, \
+ _qyy_fn, \
+ 0, 0, 0, 0); \
+ _qyy_res; \
+ })
+
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL1, \
+ _qyy_fn, \
+ _qyy_arg1, 0, 0, 0); \
+ _qyy_res; \
+ })
+
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL2, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, 0, 0); \
+ _qyy_res; \
+ })
+
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL3, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, \
+ _qyy_arg3, 0); \
+ _qyy_res; \
+ })
+
+
+/* Counts the number of errors that have been recorded by a tool. Nb:
+ the tool must record the errors with VG_(maybe_record_error)() or
+ VG_(unique_error)() for them to be counted. */
+#define VALGRIND_COUNT_ERRORS \
+ __extension__ \
+ ({unsigned int _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__COUNT_ERRORS, \
+ 0, 0, 0, 0, 0); \
+ _qyy_res; \
+ })
+
+/* Mark a block of memory as having been allocated by a malloc()-like
+ function. `addr' is the start of the usable block (ie. after any
+ redzone) `rzB' is redzone size if the allocator can apply redzones;
+ use '0' if not. Adding redzones makes it more likely Valgrind will spot
+ block overruns. `is_zeroed' indicates if the memory is zeroed, as it is
+ for calloc(). Put it immediately after the point where a block is
+ allocated.
+
+ If you're using Memcheck: If you're allocating memory via superblocks,
+ and then handing out small chunks of each superblock, if you don't have
+ redzones on your small blocks, it's worth marking the superblock with
+ VALGRIND_MAKE_MEM_NOACCESS when it's created, so that block overruns are
+ detected. But if you can put redzones on, it's probably better to not do
+ this, so that messages for small overruns are described in terms of the
+ small block rather than the superblock (but if you have a big overrun
+ that skips over a redzone, you could miss an error this way). See
+ memcheck/tests/custom_alloc.c for an example.
+
+ WARNING: if your allocator uses malloc() or 'new' to allocate
+ superblocks, rather than mmap() or brk(), this will not work properly --
+ you'll likely get assertion failures during leak detection. This is
+ because Valgrind doesn't like seeing overlapping heap blocks. Sorry.
+
+ Nb: block must be freed via a free()-like function specified
+ with VALGRIND_FREELIKE_BLOCK or mismatch errors will occur. */
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MALLOCLIKE_BLOCK, \
+ addr, sizeB, rzB, is_zeroed, 0); \
+ }
+
+/* Mark a block of memory as having been freed by a free()-like function.
+ `rzB' is redzone size; it must match that given to
+ VALGRIND_MALLOCLIKE_BLOCK. Memory not freed will be detected by the leak
+ checker. Put it immediately after the point where the block is freed. */
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__FREELIKE_BLOCK, \
+ addr, rzB, 0, 0, 0); \
+ }
+
+/* Create a memory pool. */
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__CREATE_MEMPOOL, \
+ pool, rzB, is_zeroed, 0, 0); \
+ }
+
+/* Destroy a memory pool. */
+#define VALGRIND_DESTROY_MEMPOOL(pool) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DESTROY_MEMPOOL, \
+ pool, 0, 0, 0, 0); \
+ }
+
+/* Associate a piece of memory with a memory pool. */
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_ALLOC, \
+ pool, addr, size, 0, 0); \
+ }
+
+/* Disassociate a piece of memory from a memory pool. */
+#define VALGRIND_MEMPOOL_FREE(pool, addr) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_FREE, \
+ pool, addr, 0, 0, 0); \
+ }
+
+/* Disassociate any pieces outside a particular range. */
+#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_TRIM, \
+ pool, addr, size, 0, 0); \
+ }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MOVE_MEMPOOL, \
+ poolA, poolB, 0, 0, 0); \
+ }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_CHANGE, \
+ pool, addrA, addrB, size, 0); \
+ }
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool) \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_EXISTS, \
+ pool, 0, 0, 0, 0); \
+ _qzz_res; \
+ })
+
+/* Mark a piece of memory as being a stack. Returns a stack id. */
+#define VALGRIND_STACK_REGISTER(start, end) \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_REGISTER, \
+ start, end, 0, 0, 0); \
+ _qzz_res; \
+ })
+
+/* Unmark the piece of memory associated with a stack id as being a
+ stack. */
+#define VALGRIND_STACK_DEREGISTER(id) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_DEREGISTER, \
+ id, 0, 0, 0, 0); \
+ }
+
+/* Change the start and end address of the stack id. */
+#define VALGRIND_STACK_CHANGE(id, start, end) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_CHANGE, \
+ id, start, end, 0, 0); \
+ }
+
+
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_ppc32_aix5
+#undef PLAT_ppc64_aix5
+
+#endif /* __VALGRIND_H */
+
+
diff --git a/src/testlib/qabstracttestlogger.cpp b/src/testlib/qabstracttestlogger.cpp
new file mode 100644
index 0000000000..c2e53e623e
--- /dev/null
+++ b/src/testlib/qabstracttestlogger.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qabstracttestlogger_p.h"
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/qtestassert.h"
+
+#include "QtCore/qbytearray.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#ifndef Q_OS_WIN
+#include <unistd.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest
+{
+ static FILE *stream = 0;
+}
+
+void QAbstractTestLogger::outputString(const char *msg)
+{
+ QTEST_ASSERT(QTest::stream);
+
+ ::fputs(msg, QTest::stream);
+ ::fflush(QTest::stream);
+}
+
+bool QAbstractTestLogger::isTtyOutput()
+{
+ QTEST_ASSERT(QTest::stream);
+
+#if defined(Q_OS_WIN) || defined(Q_OS_INTEGRITY)
+ return true;
+#else
+ static bool ttyoutput = isatty(fileno(QTest::stream));
+ return ttyoutput;
+#endif
+}
+
+
+void QAbstractTestLogger::startLogging()
+{
+ QTEST_ASSERT(!QTest::stream);
+
+ const char *out = QTestLog::outputFileName();
+ if (!out) {
+ QTest::stream = stdout;
+ return;
+ }
+#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE)
+ if (::fopen_s(&QTest::stream, out, "wt")) {
+#else
+ QTest::stream = ::fopen(out, "wt");
+ if (!QTest::stream) {
+#endif
+ printf("Unable to open file for logging: %s", out);
+ ::exit(1);
+ }
+}
+
+void QAbstractTestLogger::stopLogging()
+{
+ QTEST_ASSERT(QTest::stream);
+ if (QTest::stream != stdout) {
+ fclose(QTest::stream);
+ } else {
+#ifdef Q_OS_SYMBIAN
+ // Convenience sleep for Symbian and TRK. Without this sleep depending on the timing the
+ // user would not see the complete output because it is still pending in any of the buffers
+ // before arriving via the USB port on the development PC
+ User::AfterHighRes(2*1000*1000);
+#endif
+ }
+ QTest::stream = 0;
+}
+
+namespace QTest
+{
+
+extern void filter_unprintable(char *str);
+
+/*!
+ \fn int QTest::qt_asprintf(QTestCharBuffer *buf, const char *format, ...);
+ \internal
+ */
+int qt_asprintf(QTestCharBuffer *str, const char *format, ...)
+{
+ static const int MAXSIZE = 1024*1024*2;
+
+ Q_ASSERT(str);
+
+ int size = str->size();
+
+ va_list ap;
+ int res = 0;
+
+ for (;;) {
+ va_start(ap, format);
+ res = qvsnprintf(str->data(), size, format, ap);
+ va_end(ap);
+ str->data()[size - 1] = '\0';
+ if (res >= 0 && res < size) {
+ // We succeeded
+ break;
+ }
+ // buffer wasn't big enough, try again.
+ // Note, we're assuming that a result of -1 is always due to running out of space.
+ size *= 2;
+ if (size > MAXSIZE) {
+ break;
+ }
+ if (!str->reset(size))
+ break; // out of memory - take what we have
+ }
+
+ filter_unprintable(str->data());
+
+ return res;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h
new file mode 100644
index 0000000000..d116a6efb5
--- /dev/null
+++ b/src/testlib/qabstracttestlogger_p.h
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTTESTLOGGER_P_H
+#define QABSTRACTTESTLOGGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBenchmarkResult;
+
+class QAbstractTestLogger
+{
+public:
+ enum IncidentTypes {
+ Pass,
+ XFail,
+ Fail,
+ XPass
+ };
+
+ enum MessageTypes {
+ Warn,
+ QWarning,
+ QDebug,
+ QSystem,
+ QFatal,
+ Skip,
+ Info
+ };
+
+ QAbstractTestLogger() {}
+ virtual ~QAbstractTestLogger() {}
+
+ virtual void startLogging();
+ virtual void stopLogging();
+
+ virtual void enterTestFunction(const char *function) = 0;
+ virtual void leaveTestFunction() = 0;
+
+ virtual void addIncident(IncidentTypes type, const char *description,
+ const char *file = 0, int line = 0) = 0;
+ virtual void addBenchmarkResult(const QBenchmarkResult &result) = 0;
+
+ virtual void addMessage(MessageTypes type, const char *message,
+ const char *file = 0, int line = 0) = 0;
+
+ virtual void registerRandomSeed(unsigned int seed) = 0;
+
+ static void outputString(const char *msg);
+ static bool isTtyOutput();
+};
+
+struct QTestCharBuffer
+{
+ enum { InitialSize = 512 };
+
+ inline QTestCharBuffer()
+ : _size(InitialSize), buf(staticBuf)
+ {
+ staticBuf[0] = '\0';
+ }
+
+ inline ~QTestCharBuffer()
+ {
+ if (buf != staticBuf)
+ qFree(buf);
+ }
+
+ inline char *data()
+ {
+ return buf;
+ }
+
+ inline char **buffer()
+ {
+ return &buf;
+ }
+
+ inline const char* constData() const
+ {
+ return buf;
+ }
+
+ inline int size() const
+ {
+ return _size;
+ }
+
+ inline bool reset(int newSize)
+ {
+ char *newBuf = 0;
+ if (buf == staticBuf) {
+ // if we point to our internal buffer, we need to malloc first
+ newBuf = reinterpret_cast<char *>(qMalloc(newSize));
+ } else {
+ // if we already malloc'ed, just realloc
+ newBuf = reinterpret_cast<char *>(qRealloc(buf, newSize));
+ }
+
+ // if the allocation went wrong (newBuf == 0), we leave the object as is
+ if (!newBuf)
+ return false;
+
+ _size = newSize;
+ buf = newBuf;
+ return true;
+ }
+
+private:
+ int _size;
+ char* buf;
+ char staticBuf[InitialSize];
+};
+
+namespace QTest
+{
+ int qt_asprintf(QTestCharBuffer *buf, const char *format, ...);
+}
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qasciikey.cpp b/src/testlib/qasciikey.cpp
new file mode 100644
index 0000000000..42bc42e9d1
--- /dev/null
+++ b/src/testlib/qasciikey.cpp
@@ -0,0 +1,505 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/qtestcase.h"
+#include "QtTest/qtestassert.h"
+
+QT_BEGIN_NAMESPACE
+
+/*! \internal
+ Convert an ascii char key value to a Qt Key value.
+ If the key is unknown a 0 is returned.
+
+ Note: this may happen more than you like since not all known
+ ascii keys _are_ converted already. So feel free to add all the keys you need.
+ */
+Qt::Key QTest::asciiToKey(char ascii)
+{
+ switch ((unsigned char)ascii) {
+ case 0x08: return Qt::Key_Backspace;
+ case 0x09: return Qt::Key_Tab;
+ case 0x0b: return Qt::Key_Backtab;
+ case 0x0d: return Qt::Key_Return;
+ case 0x1b: return Qt::Key_Escape;
+ case 0x20: return Qt::Key_Space;
+ case 0x21: return Qt::Key_Exclam;
+ case 0x22: return Qt::Key_QuoteDbl;
+ case 0x23: return Qt::Key_NumberSign;
+ case 0x24: return Qt::Key_Dollar;
+ case 0x25: return Qt::Key_Percent;
+ case 0x26: return Qt::Key_Ampersand;
+ case 0x27: return Qt::Key_Apostrophe;
+ case 0x28: return Qt::Key_ParenLeft;
+ case 0x29: return Qt::Key_ParenRight;
+ case 0x2a: return Qt::Key_Asterisk;
+ case 0x2b: return Qt::Key_Plus;
+ case 0x2c: return Qt::Key_Comma;
+ case 0x2d: return Qt::Key_Minus;
+ case 0x2e: return Qt::Key_Period;
+ case 0x2f: return Qt::Key_Slash;
+ case 0x30: return Qt::Key_0;
+ case 0x31: return Qt::Key_1;
+ case 0x32: return Qt::Key_2;
+ case 0x33: return Qt::Key_3;
+ case 0x34: return Qt::Key_4;
+ case 0x35: return Qt::Key_5;
+ case 0x36: return Qt::Key_6;
+ case 0x37: return Qt::Key_7;
+ case 0x38: return Qt::Key_8;
+ case 0x39: return Qt::Key_9;
+ case 0x3a: return Qt::Key_Colon;
+ case 0x3b: return Qt::Key_Semicolon;
+ case 0x3c: return Qt::Key_Less;
+ case 0x3d: return Qt::Key_Equal;
+ case 0x3e: return Qt::Key_Greater;
+ case 0x3f: return Qt::Key_Question;
+ case 0x40: return Qt::Key_At;
+ case 0x41: return Qt::Key_A;
+ case 0x42: return Qt::Key_B;
+ case 0x43: return Qt::Key_C;
+ case 0x44: return Qt::Key_D;
+ case 0x45: return Qt::Key_E;
+ case 0x46: return Qt::Key_F;
+ case 0x47: return Qt::Key_G;
+ case 0x48: return Qt::Key_H;
+ case 0x49: return Qt::Key_I;
+ case 0x4a: return Qt::Key_J;
+ case 0x4b: return Qt::Key_K;
+ case 0x4c: return Qt::Key_L;
+ case 0x4d: return Qt::Key_M;
+ case 0x4e: return Qt::Key_N;
+ case 0x4f: return Qt::Key_O;
+ case 0x50: return Qt::Key_P;
+ case 0x51: return Qt::Key_Q;
+ case 0x52: return Qt::Key_R;
+ case 0x53: return Qt::Key_S;
+ case 0x54: return Qt::Key_T;
+ case 0x55: return Qt::Key_U;
+ case 0x56: return Qt::Key_V;
+ case 0x57: return Qt::Key_W;
+ case 0x58: return Qt::Key_X;
+ case 0x59: return Qt::Key_Y;
+ case 0x5a: return Qt::Key_Z;
+ case 0x5b: return Qt::Key_BracketLeft;
+ case 0x5c: return Qt::Key_Backslash;
+ case 0x5d: return Qt::Key_BracketRight;
+ case 0x5e: return Qt::Key_AsciiCircum;
+ case 0x5f: return Qt::Key_Underscore;
+ case 0x60: return Qt::Key_QuoteLeft;
+ case 0x61: return Qt::Key_A;
+ case 0x62: return Qt::Key_B;
+ case 0x63: return Qt::Key_C;
+ case 0x64: return Qt::Key_D;
+ case 0x65: return Qt::Key_E;
+ case 0x66: return Qt::Key_F;
+ case 0x67: return Qt::Key_G;
+ case 0x68: return Qt::Key_H;
+ case 0x69: return Qt::Key_I;
+ case 0x6a: return Qt::Key_J;
+ case 0x6b: return Qt::Key_K;
+ case 0x6c: return Qt::Key_L;
+ case 0x6d: return Qt::Key_M;
+ case 0x6e: return Qt::Key_N;
+ case 0x6f: return Qt::Key_O;
+ case 0x70: return Qt::Key_P;
+ case 0x71: return Qt::Key_Q;
+ case 0x72: return Qt::Key_R;
+ case 0x73: return Qt::Key_S;
+ case 0x74: return Qt::Key_T;
+ case 0x75: return Qt::Key_U;
+ case 0x76: return Qt::Key_V;
+ case 0x77: return Qt::Key_W;
+ case 0x78: return Qt::Key_X;
+ case 0x79: return Qt::Key_Y;
+ case 0x7a: return Qt::Key_Z;
+ case 0x7b: return Qt::Key_BraceLeft;
+ case 0x7c: return Qt::Key_Bar;
+ case 0x7d: return Qt::Key_BraceRight;
+ case 0x7e: return Qt::Key_AsciiTilde;
+
+ // Latin 1 codes adapted from X: keysymdef.h,v 1.21 94/08/28 16:17:06
+ case 0xa0: return Qt::Key_nobreakspace;
+ case 0xa1: return Qt::Key_exclamdown;
+ case 0xa2: return Qt::Key_cent;
+ case 0xa3: return Qt::Key_sterling;
+ case 0xa4: return Qt::Key_currency;
+ case 0xa5: return Qt::Key_yen;
+ case 0xa6: return Qt::Key_brokenbar;
+ case 0xa7: return Qt::Key_section;
+ case 0xa8: return Qt::Key_diaeresis;
+ case 0xa9: return Qt::Key_copyright;
+ case 0xaa: return Qt::Key_ordfeminine;
+ case 0xab: return Qt::Key_guillemotleft;
+ case 0xac: return Qt::Key_notsign;
+ case 0xad: return Qt::Key_hyphen;
+ case 0xae: return Qt::Key_registered;
+ case 0xaf: return Qt::Key_macron;
+ case 0xb0: return Qt::Key_degree;
+ case 0xb1: return Qt::Key_plusminus;
+ case 0xb2: return Qt::Key_twosuperior;
+ case 0xb3: return Qt::Key_threesuperior;
+ case 0xb4: return Qt::Key_acute;
+ case 0xb5: return Qt::Key_mu;
+ case 0xb6: return Qt::Key_paragraph;
+ case 0xb7: return Qt::Key_periodcentered;
+ case 0xb8: return Qt::Key_cedilla;
+ case 0xb9: return Qt::Key_onesuperior;
+ case 0xba: return Qt::Key_masculine;
+ case 0xbb: return Qt::Key_guillemotright;
+ case 0xbc: return Qt::Key_onequarter;
+ case 0xbd: return Qt::Key_onehalf;
+ case 0xbe: return Qt::Key_threequarters;
+ case 0xbf: return Qt::Key_questiondown;
+ case 0xc0: return Qt::Key_Agrave;
+ case 0xc1: return Qt::Key_Aacute;
+ case 0xc2: return Qt::Key_Acircumflex;
+ case 0xc3: return Qt::Key_Atilde;
+ case 0xc4: return Qt::Key_Adiaeresis;
+ case 0xc5: return Qt::Key_Aring;
+ case 0xc6: return Qt::Key_AE;
+ case 0xc7: return Qt::Key_Ccedilla;
+ case 0xc8: return Qt::Key_Egrave;
+ case 0xc9: return Qt::Key_Eacute;
+ case 0xca: return Qt::Key_Ecircumflex;
+ case 0xcb: return Qt::Key_Ediaeresis;
+ case 0xcc: return Qt::Key_Igrave;
+ case 0xcd: return Qt::Key_Iacute;
+ case 0xce: return Qt::Key_Icircumflex;
+ case 0xcf: return Qt::Key_Idiaeresis;
+ case 0xd0: return Qt::Key_ETH;
+ case 0xd1: return Qt::Key_Ntilde;
+ case 0xd2: return Qt::Key_Ograve;
+ case 0xd3: return Qt::Key_Oacute;
+ case 0xd4: return Qt::Key_Ocircumflex;
+ case 0xd5: return Qt::Key_Otilde;
+ case 0xd6: return Qt::Key_Odiaeresis;
+ case 0xd7: return Qt::Key_multiply;
+ case 0xd8: return Qt::Key_Ooblique;
+ case 0xd9: return Qt::Key_Ugrave;
+ case 0xda: return Qt::Key_Uacute;
+ case 0xdb: return Qt::Key_Ucircumflex;
+ case 0xdc: return Qt::Key_Udiaeresis;
+ case 0xdd: return Qt::Key_Yacute;
+ case 0xde: return Qt::Key_THORN;
+ case 0xdf: return Qt::Key_ssharp;
+ case 0xe5: return Qt::Key_Aring;
+ case 0xe6: return Qt::Key_AE;
+ case 0xf7: return Qt::Key_division;
+ case 0xf8: return Qt::Key_Ooblique;
+ case 0xff: return Qt::Key_ydiaeresis;
+ default: QTEST_ASSERT(false); return Qt::Key(0);
+ }
+}
+
+/*! \internal
+ Convert a Qt Key to an ascii char value.
+ If the Qt key is unknown a 0 is returned.
+
+ Note: this may happen more than you like since not all known
+ Qt keys _are_ converted already. So feel free to add all the keys you need.
+*/
+char QTest::keyToAscii(Qt::Key key)
+{
+ switch (key) {
+ case Qt::Key_Backspace: return 0x8; //BS
+ case Qt::Key_Tab: return 0x09; // HT
+ case Qt::Key_Backtab: return 0x0b; // VT
+ case Qt::Key_Enter:
+ case Qt::Key_Return: return 0x0d; // CR
+ case Qt::Key_Escape: return 0x1b; // ESC
+ case Qt::Key_Space: return 0x20; // 7 bit printable ASCII
+ case Qt::Key_Exclam: return 0x21;
+ case Qt::Key_QuoteDbl: return 0x22;
+ case Qt::Key_NumberSign: return 0x23;
+ case Qt::Key_Dollar: return 0x24;
+ case Qt::Key_Percent: return 0x25;
+ case Qt::Key_Ampersand: return 0x26;
+ case Qt::Key_Apostrophe: return 0x27;
+ case Qt::Key_ParenLeft: return 0x28;
+ case Qt::Key_ParenRight: return 0x29;
+ case Qt::Key_Asterisk: return 0x2a;
+ case Qt::Key_Plus: return 0x2b;
+ case Qt::Key_Comma: return 0x2c;
+ case Qt::Key_Minus: return 0x2d;
+ case Qt::Key_Period: return 0x2e;
+ case Qt::Key_Slash: return 0x2f;
+ case Qt::Key_0: return 0x30;
+ case Qt::Key_1: return 0x31;
+ case Qt::Key_2: return 0x32;
+ case Qt::Key_3: return 0x33;
+ case Qt::Key_4: return 0x34;
+ case Qt::Key_5: return 0x35;
+ case Qt::Key_6: return 0x36;
+ case Qt::Key_7: return 0x37;
+ case Qt::Key_8: return 0x38;
+ case Qt::Key_9: return 0x39;
+ case Qt::Key_Colon: return 0x3a;
+ case Qt::Key_Semicolon: return 0x3b;
+ case Qt::Key_Less: return 0x3c;
+ case Qt::Key_Equal: return 0x3d;
+ case Qt::Key_Greater: return 0x3e;
+ case Qt::Key_Question: return 0x3f;
+ case Qt::Key_At: return 0x40;
+ case Qt::Key_A: return 0x61; // 0x41 == 'A', 0x61 == 'a'
+ case Qt::Key_B: return 0x62;
+ case Qt::Key_C: return 0x63;
+ case Qt::Key_D: return 0x64;
+ case Qt::Key_E: return 0x65;
+ case Qt::Key_F: return 0x66;
+ case Qt::Key_G: return 0x67;
+ case Qt::Key_H: return 0x68;
+ case Qt::Key_I: return 0x69;
+ case Qt::Key_J: return 0x6a;
+ case Qt::Key_K: return 0x6b;
+ case Qt::Key_L: return 0x6c;
+ case Qt::Key_M: return 0x6d;
+ case Qt::Key_N: return 0x6e;
+ case Qt::Key_O: return 0x6f;
+ case Qt::Key_P: return 0x70;
+ case Qt::Key_Q: return 0x71;
+ case Qt::Key_R: return 0x72;
+ case Qt::Key_S: return 0x73;
+ case Qt::Key_T: return 0x74;
+ case Qt::Key_U: return 0x75;
+ case Qt::Key_V: return 0x76;
+ case Qt::Key_W: return 0x77;
+ case Qt::Key_X: return 0x78;
+ case Qt::Key_Y: return 0x79;
+ case Qt::Key_Z: return 0x7a;
+ case Qt::Key_BracketLeft: return 0x5b;
+ case Qt::Key_Backslash: return 0x5c;
+ case Qt::Key_BracketRight: return 0x5d;
+ case Qt::Key_AsciiCircum: return 0x5e;
+ case Qt::Key_Underscore: return 0x5f;
+ case Qt::Key_QuoteLeft: return 0x60;
+
+ case Qt::Key_BraceLeft: return 0x7b;
+ case Qt::Key_Bar: return 0x7c;
+ case Qt::Key_BraceRight: return 0x7d;
+ case Qt::Key_AsciiTilde: return 0x7e;
+
+ case Qt::Key_Delete: return 0;
+ case Qt::Key_Insert: return 0; // = 0x1006,
+ case Qt::Key_Pause: return 0; // = 0x1008,
+ case Qt::Key_Print: return 0; // = 0x1009,
+ case Qt::Key_SysReq: return 0; // = 0x100a,
+
+ case Qt::Key_Clear: return 0; // = 0x100b,
+
+ case Qt::Key_Home: return 0; // = 0x1010, // cursor movement
+ case Qt::Key_End: return 0; // = 0x1011,
+ case Qt::Key_Left: return 0; // = 0x1012,
+ case Qt::Key_Up: return 0; // = 0x1013,
+ case Qt::Key_Right: return 0; // = 0x1014,
+ case Qt::Key_Down: return 0; // = 0x1015,
+ case Qt::Key_PageUp: return 0; // = 0x1016,
+ case Qt::Key_PageDown: return 0; // = 0x1017,
+ case Qt::Key_Shift: return 0; // = 0x1020, // modifiers
+ case Qt::Key_Control: return 0; // = 0x1021,
+ case Qt::Key_Meta: return 0; // = 0x1022,
+ case Qt::Key_Alt: return 0; // = 0x1023,
+ case Qt::Key_CapsLock: return 0; // = 0x1024,
+ case Qt::Key_NumLock: return 0; // = 0x1025,
+ case Qt::Key_ScrollLock: return 0; // = 0x1026,
+ case Qt::Key_F1: return 0; // = 0x1030, // function keys
+ case Qt::Key_F2: return 0; // = 0x1031,
+ case Qt::Key_F3: return 0; // = 0x1032,
+ case Qt::Key_F4: return 0; // = 0x1033,
+ case Qt::Key_F5: return 0; // = 0x1034,
+ case Qt::Key_F6: return 0; // = 0x1035,
+ case Qt::Key_F7: return 0; // = 0x1036,
+ case Qt::Key_F8: return 0; // = 0x1037,
+ case Qt::Key_F9: return 0; // = 0x1038,
+ case Qt::Key_F10: return 0; // = 0x1039,
+ case Qt::Key_F11: return 0; // = 0x103a,
+ case Qt::Key_F12: return 0; // = 0x103b,
+ case Qt::Key_F13: return 0; // = 0x103c,
+ case Qt::Key_F14: return 0; // = 0x103d,
+ case Qt::Key_F15: return 0; // = 0x103e,
+ case Qt::Key_F16: return 0; // = 0x103f,
+ case Qt::Key_F17: return 0; // = 0x1040,
+ case Qt::Key_F18: return 0; // = 0x1041,
+ case Qt::Key_F19: return 0; // = 0x1042,
+ case Qt::Key_F20: return 0; // = 0x1043,
+ case Qt::Key_F21: return 0; // = 0x1044,
+ case Qt::Key_F22: return 0; // = 0x1045,
+ case Qt::Key_F23: return 0; // = 0x1046,
+ case Qt::Key_F24: return 0; // = 0x1047,
+ case Qt::Key_F25: return 0; // = 0x1048, // F25 .. F35 only on X11
+ case Qt::Key_F26: return 0; // = 0x1049,
+ case Qt::Key_F27: return 0; // = 0x104a,
+ case Qt::Key_F28: return 0; // = 0x104b,
+ case Qt::Key_F29: return 0; // = 0x104c,
+ case Qt::Key_F30: return 0; // = 0x104d,
+ case Qt::Key_F31: return 0; // = 0x104e,
+ case Qt::Key_F32: return 0; // = 0x104f,
+ case Qt::Key_F33: return 0; // = 0x1050,
+ case Qt::Key_F34: return 0; // = 0x1051,
+ case Qt::Key_F35: return 0; // = 0x1052,
+ case Qt::Key_Super_L: return 0; // = 0x1053, // extra keys
+ case Qt::Key_Super_R: return 0; // = 0x1054,
+ case Qt::Key_Menu: return 0; // = 0x1055,
+ case Qt::Key_Hyper_L: return 0; // = 0x1056,
+ case Qt::Key_Hyper_R: return 0; // = 0x1057,
+ case Qt::Key_Help: return 0; // = 0x1058,
+ case Qt::Key_Direction_L: return 0; // = 0x1059,
+ case Qt::Key_Direction_R: return 0; // = 0x1060,
+
+ // Latin 1 codes adapted from X: keysymdef.h,v 1.21 94/08/28 16:17:06
+ case Qt::Key_nobreakspace: return char(0xa0);
+ case Qt::Key_exclamdown: return char(0xa1);
+ case Qt::Key_cent: return char(0xa2);
+ case Qt::Key_sterling: return char(0xa3);
+ case Qt::Key_currency: return char(0xa4);
+ case Qt::Key_yen: return char(0xa5);
+ case Qt::Key_brokenbar: return char(0xa6);
+ case Qt::Key_section: return char(0xa7);
+ case Qt::Key_diaeresis: return char(0xa8);
+ case Qt::Key_copyright: return char(0xa9);
+ case Qt::Key_ordfeminine: return char(0xaa);
+ case Qt::Key_guillemotleft: return char(0xab); // left angle quotation mar
+ case Qt::Key_notsign: return char(0xac);
+ case Qt::Key_hyphen: return char(0xad);
+ case Qt::Key_registered: return char(0xae);
+ case Qt::Key_macron: return char(0xaf);
+ case Qt::Key_degree: return char(0xb0);
+ case Qt::Key_plusminus: return char(0xb1);
+ case Qt::Key_twosuperior: return char(0xb2);
+ case Qt::Key_threesuperior: return char(0xb3);
+ case Qt::Key_acute: return char(0xb4);
+ case Qt::Key_mu: return char(0xb5);
+ case Qt::Key_paragraph: return char(0xb6);
+ case Qt::Key_periodcentered: return char(0xb7);
+ case Qt::Key_cedilla: return char(0xb8);
+ case Qt::Key_onesuperior: return char(0xb9);
+ case Qt::Key_masculine: return char(0xba);
+ case Qt::Key_guillemotright: return char(0xbb); // right angle quotation mar
+ case Qt::Key_onequarter: return char(0xbc);
+ case Qt::Key_onehalf: return char(0xbd);
+ case Qt::Key_threequarters: return char(0xbe);
+ case Qt::Key_questiondown: return char(0xbf);
+ case Qt::Key_Agrave: return char(0xc0);
+ case Qt::Key_Aacute: return char(0xc1);
+ case Qt::Key_Acircumflex: return char(0xc2);
+ case Qt::Key_Atilde: return char(0xc3);
+ case Qt::Key_Adiaeresis: return char(0xc4);
+ case Qt::Key_Aring: return char(0xe5);
+ case Qt::Key_AE: return char(0xe6);
+ case Qt::Key_Ccedilla: return char(0xc7);
+ case Qt::Key_Egrave: return char(0xc8);
+ case Qt::Key_Eacute: return char(0xc9);
+ case Qt::Key_Ecircumflex: return char(0xca);
+ case Qt::Key_Ediaeresis: return char(0xcb);
+ case Qt::Key_Igrave: return char(0xcc);
+ case Qt::Key_Iacute: return char(0xcd);
+ case Qt::Key_Icircumflex: return char(0xce);
+ case Qt::Key_Idiaeresis: return char(0xcf);
+ case Qt::Key_ETH: return char(0xd0);
+ case Qt::Key_Ntilde: return char(0xd1);
+ case Qt::Key_Ograve: return char(0xd2);
+ case Qt::Key_Oacute: return char(0xd3);
+ case Qt::Key_Ocircumflex: return char(0xd4);
+ case Qt::Key_Otilde: return char(0xd5);
+ case Qt::Key_Odiaeresis: return char(0xd6);
+ case Qt::Key_multiply: return char(0xd7);
+ case Qt::Key_Ooblique: return char(0xf8);
+ case Qt::Key_Ugrave: return char(0xd9);
+ case Qt::Key_Uacute: return char(0xda);
+ case Qt::Key_Ucircumflex: return char(0xdb);
+ case Qt::Key_Udiaeresis: return char(0xdc);
+ case Qt::Key_Yacute: return char(0xdd);
+ case Qt::Key_THORN: return char(0xde);
+ case Qt::Key_ssharp: return char(0xdf);
+ case Qt::Key_division: return char(0xf7);
+ case Qt::Key_ydiaeresis: return char(0xff);
+
+ // multimedia/internet keys - ignored by default - see QKeyEvent c'tor
+
+ case Qt::Key_Back : return 0; // = 0x1061,
+ case Qt::Key_Forward : return 0; // = 0x1062,
+ case Qt::Key_Stop : return 0; // = 0x1063,
+ case Qt::Key_Refresh : return 0; // = 0x1064,
+
+ case Qt::Key_VolumeDown: return 0; // = 0x1070,
+ case Qt::Key_VolumeMute : return 0; // = 0x1071,
+ case Qt::Key_VolumeUp: return 0; // = 0x1072,
+ case Qt::Key_BassBoost: return 0; // = 0x1073,
+ case Qt::Key_BassUp: return 0; // = 0x1074,
+ case Qt::Key_BassDown: return 0; // = 0x1075,
+ case Qt::Key_TrebleUp: return 0; // = 0x1076,
+ case Qt::Key_TrebleDown: return 0; // = 0x1077,
+
+ case Qt::Key_MediaPlay : return 0; // = 0x1080,
+ case Qt::Key_MediaStop : return 0; // = 0x1081,
+ case Qt::Key_MediaPrevious : return 0; // = 0x1082,
+ case Qt::Key_MediaNext : return 0; // = 0x1083,
+ case Qt::Key_MediaRecord: return 0; // = 0x1084,
+
+ case Qt::Key_HomePage : return 0; // = 0x1090,
+ case Qt::Key_Favorites : return 0; // = 0x1091,
+ case Qt::Key_Search : return 0; // = 0x1092,
+ case Qt::Key_Standby: return 0; // = 0x1093,
+ case Qt::Key_OpenUrl: return 0; // = 0x1094,
+
+ case Qt::Key_LaunchMail : return 0; // = 0x10a0,
+ case Qt::Key_LaunchMedia: return 0; // = 0x10a1,
+ case Qt::Key_Launch0 : return 0; // = 0x10a2,
+ case Qt::Key_Launch1 : return 0; // = 0x10a3,
+ case Qt::Key_Launch2 : return 0; // = 0x10a4,
+ case Qt::Key_Launch3 : return 0; // = 0x10a5,
+ case Qt::Key_Launch4 : return 0; // = 0x10a6,
+ case Qt::Key_Launch5 : return 0; // = 0x10a7,
+ case Qt::Key_Launch6 : return 0; // = 0x10a8,
+ case Qt::Key_Launch7 : return 0; // = 0x10a9,
+ case Qt::Key_Launch8 : return 0; // = 0x10aa,
+ case Qt::Key_Launch9 : return 0; // = 0x10ab,
+ case Qt::Key_LaunchA : return 0; // = 0x10ac,
+ case Qt::Key_LaunchB : return 0; // = 0x10ad,
+ case Qt::Key_LaunchC : return 0; // = 0x10ae,
+ case Qt::Key_LaunchD : return 0; // = 0x10af,
+ case Qt::Key_LaunchE : return 0; // = 0x10b0,
+ case Qt::Key_LaunchF : return 0; // = 0x10b1,
+
+ default: QTEST_ASSERT(false); return 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qbenchmark.cpp b/src/testlib/qbenchmark.cpp
new file mode 100644
index 0000000000..d933fb1d57
--- /dev/null
+++ b/src/testlib/qbenchmark.cpp
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/qbenchmark.h"
+#include "QtTest/private/qbenchmark_p.h"
+#include "QtTest/private/qbenchmarkmetric_p.h"
+
+#ifdef QT_GUI_LIB
+#include <QtGui/qapplication.h>
+#endif
+
+#include <QtCore/qprocess.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qset.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QBenchmarkGlobalData *QBenchmarkGlobalData::current;
+
+QBenchmarkGlobalData::QBenchmarkGlobalData()
+ : measurer(0)
+ , walltimeMinimum(-1)
+ , iterationCount(-1)
+ , medianIterationCount(-1)
+ , createChart(false)
+ , verboseOutput(false)
+ , mode_(WallTime)
+{
+ setMode(mode_);
+}
+
+QBenchmarkGlobalData::~QBenchmarkGlobalData()
+{
+ delete measurer;
+ QBenchmarkGlobalData::current = 0;
+}
+
+void QBenchmarkGlobalData::setMode(Mode mode)
+{
+ mode_ = mode;
+
+ if (measurer)
+ delete measurer;
+ measurer = createMeasurer();
+}
+
+QBenchmarkMeasurerBase * QBenchmarkGlobalData::createMeasurer()
+{
+ QBenchmarkMeasurerBase *measurer = 0;
+ if (0) {
+#ifdef QTESTLIB_USE_VALGRIND
+ } else if (mode_ == CallgrindChildProcess || mode_ == CallgrindParentProcess) {
+ measurer = new QBenchmarkCallgrindMeasurer;
+#endif
+#ifdef HAVE_TICK_COUNTER
+ } else if (mode_ == TickCounter) {
+ measurer = new QBenchmarkTickMeasurer;
+#endif
+ } else if (mode_ == EventCounter) {
+ measurer = new QBenchmarkEvent;
+ } else {
+ measurer = new QBenchmarkTimeMeasurer;
+ }
+ measurer->init();
+ return measurer;
+}
+
+int QBenchmarkGlobalData::adjustMedianIterationCount()
+{
+ if (medianIterationCount != -1) {
+ return medianIterationCount;
+ } else {
+ return measurer->adjustMedianCount(1);
+ }
+}
+
+
+QBenchmarkTestMethodData *QBenchmarkTestMethodData::current;
+
+QBenchmarkTestMethodData::QBenchmarkTestMethodData()
+:resultAccepted(false), runOnce(false), iterationCount(-1)
+{
+
+}
+
+QBenchmarkTestMethodData::~QBenchmarkTestMethodData()
+{
+ QBenchmarkTestMethodData::current = 0;
+}
+
+void QBenchmarkTestMethodData::beginDataRun()
+{
+ iterationCount = adjustIterationCount(1);
+}
+
+void QBenchmarkTestMethodData::endDataRun()
+{
+
+}
+
+int QBenchmarkTestMethodData::adjustIterationCount(int suggestion)
+{
+ // Let the -iterations option override the measurer.
+ if (QBenchmarkGlobalData::current->iterationCount != -1) {
+ iterationCount = QBenchmarkGlobalData::current->iterationCount;
+ } else {
+ iterationCount = QBenchmarkGlobalData::current->measurer->adjustIterationCount(suggestion);
+ }
+
+ return iterationCount;
+}
+
+void QBenchmarkTestMethodData::setResult(
+ qreal value, QTest::QBenchmarkMetric metric, bool setByMacro)
+{
+ bool accepted = false;
+
+ // Always accept the result if the iteration count has been
+ // specified on the command line with -iterations.
+ if (QBenchmarkGlobalData::current->iterationCount != -1)
+ accepted = true;
+
+ else if (QBenchmarkTestMethodData::current->runOnce || !setByMacro) {
+ iterationCount = 1;
+ accepted = true;
+ }
+
+ // Test the result directly without calling the measurer if the minimum time
+ // has been specified on the command line with -minimumvalue.
+ else if (QBenchmarkGlobalData::current->walltimeMinimum != -1)
+ accepted = (value > QBenchmarkGlobalData::current->walltimeMinimum);
+ else
+ accepted = QBenchmarkGlobalData::current->measurer->isMeasurementAccepted(value);
+
+ // Accept the result or double the number of iterations.
+ if (accepted)
+ resultAccepted = true;
+ else
+ iterationCount *= 2;
+
+ this->result = QBenchmarkResult(
+ QBenchmarkGlobalData::current->context, value, iterationCount, metric, setByMacro);
+}
+
+/*!
+ \class QTest::QBenchmarkIterationController
+ \internal
+
+ The QBenchmarkIterationController class is used by the QBENCHMARK macro to
+ drive the benchmarking loop. It is repsonsible for starting and stopping
+ the timing measurements as well as calling the result reporting functions.
+*/
+
+/*! \internal
+*/
+QTest::QBenchmarkIterationController::QBenchmarkIterationController(RunMode runMode)
+{
+ i = 0;
+ if (runMode == RunOnce)
+ QBenchmarkTestMethodData::current->runOnce = true;
+ QTest::beginBenchmarkMeasurement();
+}
+
+QTest::QBenchmarkIterationController::QBenchmarkIterationController()
+{
+ i = 0;
+ QTest::beginBenchmarkMeasurement();
+}
+
+/*! \internal
+*/
+QTest::QBenchmarkIterationController::~QBenchmarkIterationController()
+{
+ const qreal result = QTest::endBenchmarkMeasurement();
+ QBenchmarkTestMethodData::current->setResult(result, QBenchmarkGlobalData::current->measurer->metricType());
+}
+
+/*! \internal
+*/
+bool QTest::QBenchmarkIterationController::isDone()
+{
+ if (QBenchmarkTestMethodData::current->runOnce)
+ return i > 0;
+ return i >= QTest::iterationCount();
+}
+
+/*! \internal
+*/
+void QTest::QBenchmarkIterationController::next()
+{
+ ++i;
+}
+
+/*! \internal
+*/
+int QTest::iterationCount()
+{
+ return QBenchmarkTestMethodData::current->iterationCount;
+}
+
+/*! \internal
+*/
+void QTest::setIterationCountHint(int count)
+{
+ QBenchmarkTestMethodData::current->adjustIterationCount(count);
+}
+
+/*! \internal
+*/
+void QTest::setIterationCount(int count)
+{
+ QBenchmarkTestMethodData::current->iterationCount = count;
+ QBenchmarkTestMethodData::current->resultAccepted = true;
+}
+
+/*! \internal
+*/
+void QTest::beginBenchmarkMeasurement()
+{
+ QBenchmarkGlobalData::current->measurer->start();
+ // the clock is ticking after the line above, don't add code here.
+}
+
+/*! \internal
+*/
+quint64 QTest::endBenchmarkMeasurement()
+{
+ // the clock is ticking before the line below, don't add code here.
+ return QBenchmarkGlobalData::current->measurer->stop();
+}
+
+/*!
+ Sets the benchmark result for this test function to \a result.
+
+ Use this function if you want to report benchmark results without
+ using the QBENCHMARK macro. Use \a metric to specify how QTestLib
+ should interpret the results.
+
+ The context for the result will be the test function name and any
+ data tag from the _data function. This function can only be called
+ once in each test function, subsequent calls will replace the
+ earlier reported results.
+
+ Note that the -iterations command line argument has no effect
+ on test functions without the QBENCHMARK macro.
+
+ \since 4.7
+*/
+void QTest::setBenchmarkResult(qreal result, QTest::QBenchmarkMetric metric)
+{
+ QBenchmarkTestMethodData::current->setResult(result, metric, false);
+}
+
+template <typename T>
+Q_TYPENAME T::value_type qAverage(const T &container)
+{
+ Q_TYPENAME T::const_iterator it = container.constBegin();
+ Q_TYPENAME T::const_iterator end = container.constEnd();
+ Q_TYPENAME T::value_type acc = Q_TYPENAME T::value_type();
+ int count = 0;
+ while (it != end) {
+ acc += *it;
+ ++it;
+ ++count;
+ }
+ return acc / count;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qbenchmark.h b/src/testlib/qbenchmark.h
new file mode 100644
index 0000000000..490f7b1c60
--- /dev/null
+++ b/src/testlib/qbenchmark.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARK_H
+#define QBENCHMARK_H
+
+#include <QtTest/qtest_global.h>
+#include <QtTest/qbenchmarkmetric.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest
+{
+
+//
+// W A R N I N G
+// -------------
+//
+// The QBenchmarkIterationController class is not a part of the
+// QTestlib API. It exists purely as an implementation detail.
+//
+//
+class Q_TESTLIB_EXPORT QBenchmarkIterationController
+{
+public:
+ enum RunMode { RepeatUntilValidMeasurement, RunOnce };
+ QBenchmarkIterationController();
+ QBenchmarkIterationController(RunMode runMode);
+ ~QBenchmarkIterationController();
+ bool isDone();
+ void next();
+ int i;
+};
+
+}
+
+// --- BEGIN public API ---
+
+#define QBENCHMARK \
+ for (QTest::QBenchmarkIterationController __iteration_controller; \
+ __iteration_controller.isDone() == false; __iteration_controller.next())
+
+#define QBENCHMARK_ONCE \
+ for (QTest::QBenchmarkIterationController __iteration_controller(QTest::QBenchmarkIterationController::RunOnce); \
+ __iteration_controller.isDone() == false; __iteration_controller.next())
+
+namespace QTest
+{
+ void Q_TESTLIB_EXPORT setBenchmarkResult(qreal result, QBenchmarkMetric metric);
+}
+
+// --- END public API ---
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QBENCHMARK_H
diff --git a/src/testlib/qbenchmark_p.h b/src/testlib/qbenchmark_p.h
new file mode 100644
index 0000000000..ace17dbe8b
--- /dev/null
+++ b/src/testlib/qbenchmark_p.h
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARK_P_H
+#define QBENCHMARK_P_H
+
+#include <stdlib.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#if (defined(Q_OS_LINUX) || defined Q_OS_MAC) && !defined(QT_NO_PROCESS)
+#define QTESTLIB_USE_VALGRIND
+#else
+#undef QTESTLIB_USE_VALGRIND
+#endif
+
+#include "QtTest/private/qbenchmarkmeasurement_p.h"
+#include <QtCore/QMap>
+#include <QtTest/qtest_global.h>
+#ifdef QTESTLIB_USE_VALGRIND
+#include "QtTest/private/qbenchmarkvalgrind_p.h"
+#endif
+#include "QtTest/private/qbenchmarkevent_p.h"
+#include "QtTest/private/qbenchmarkmetric_p.h"
+
+QT_BEGIN_NAMESPACE
+
+struct QBenchmarkContext
+{
+ // None of the strings below are assumed to contain commas (see toString() below)
+ QString slotName;
+ QString tag; // from _data() function
+
+ int checkpointIndex;
+
+ QString toString() const
+ {
+ QString s = QString::fromLatin1("%1,%2,%3").arg(slotName).arg(tag).arg(checkpointIndex);
+ return s;
+ }
+
+ QBenchmarkContext() : checkpointIndex(-1) {}
+};
+
+class QBenchmarkResult
+{
+public:
+ QBenchmarkContext context;
+ qreal value;
+ int iterations;
+ QTest::QBenchmarkMetric metric;
+ bool setByMacro;
+ bool valid;
+
+ QBenchmarkResult()
+ : value(-1)
+ , iterations(-1)
+ , setByMacro(true)
+ , valid(false)
+ { }
+
+ QBenchmarkResult(
+ const QBenchmarkContext &context, const qreal value, const int iterations,
+ QTest::QBenchmarkMetric metric, bool setByMacro)
+ : context(context)
+ , value(value)
+ , iterations(iterations)
+ , metric(metric)
+ , setByMacro(setByMacro)
+ , valid(true)
+ { }
+
+ bool operator<(const QBenchmarkResult &other) const
+ {
+ return (value / iterations) < (other.value / other.iterations);
+ }
+};
+
+/*
+ The QBenchmarkGlobalData class stores global benchmark-related data.
+ QBenchmarkGlobalData:current is created at the beginning of qExec()
+ and cleared at the end.
+*/
+class Q_TESTLIB_EXPORT QBenchmarkGlobalData
+{
+public:
+ static QBenchmarkGlobalData *current;
+
+ QBenchmarkGlobalData();
+ ~QBenchmarkGlobalData();
+ enum Mode { WallTime, CallgrindParentProcess, CallgrindChildProcess, TickCounter, EventCounter };
+ void setMode(Mode mode);
+ Mode mode() const { return mode_; }
+ QBenchmarkMeasurerBase *createMeasurer();
+ int adjustMedianIterationCount();
+
+ QBenchmarkMeasurerBase *measurer;
+ QBenchmarkContext context;
+ int walltimeMinimum;
+ int iterationCount;
+ int medianIterationCount;
+ bool createChart;
+ bool verboseOutput;
+ QString callgrindOutFileBase;
+private:
+ Mode mode_;
+};
+
+/*
+ The QBenchmarkTestMethodData class stores all benchmark-related data
+ for the current test case. QBenchmarkTestMethodData:current is
+ created at the beginning of qInvokeTestMethod() and cleared at
+ the end.
+*/
+class Q_TESTLIB_EXPORT QBenchmarkTestMethodData
+{
+public:
+ static QBenchmarkTestMethodData *current;
+ QBenchmarkTestMethodData();
+ ~QBenchmarkTestMethodData();
+
+ // Called once for each data row created by the _data function,
+ // before and after calling the test function itself.
+ void beginDataRun();
+ void endDataRun();
+
+ bool isBenchmark() const { return result.valid; }
+ bool resultsAccepted() const { return resultAccepted; }
+ int adjustIterationCount(int suggestion);
+ void setResult(qreal value, QTest::QBenchmarkMetric metric, bool setByMacro = true);
+
+ QBenchmarkResult result;
+ bool resultAccepted;
+ bool runOnce;
+ int iterationCount;
+};
+
+// low-level API:
+namespace QTest
+{
+ int iterationCount();
+ void setIterationCountHint(int count);
+ void setIterationCount(int count);
+
+ Q_TESTLIB_EXPORT void beginBenchmarkMeasurement();
+ Q_TESTLIB_EXPORT quint64 endBenchmarkMeasurement();
+}
+
+QT_END_NAMESPACE
+
+#endif // QBENCHMARK_H
diff --git a/src/testlib/qbenchmarkevent.cpp b/src/testlib/qbenchmarkevent.cpp
new file mode 100644
index 0000000000..3dcf124d17
--- /dev/null
+++ b/src/testlib/qbenchmarkevent.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qbenchmarkevent_p.h"
+#include "QtTest/private/qbenchmark_p.h"
+#include "QtTest/private/qbenchmarkmetric_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QAbstractEventDispatcher::EventFilter oldEventFilter = 0;
+qint64 QBenchmarkEvent::eventCounter = 0;
+
+QBenchmarkEvent::~QBenchmarkEvent()
+{
+}
+
+void QBenchmarkEvent::start()
+{
+ QBenchmarkEvent::eventCounter = 0;
+ QAbstractEventDispatcher *parent = QAbstractEventDispatcher::instance();
+ oldEventFilter = parent->setEventFilter(QBenchmarkEvent::eventCountingMechanism);
+}
+
+qint64 QBenchmarkEvent::checkpoint()
+{
+ return QBenchmarkEvent::eventCounter;
+}
+
+qint64 QBenchmarkEvent::stop()
+{
+ QAbstractEventDispatcher *parent = QAbstractEventDispatcher::instance();
+ parent->setEventFilter(oldEventFilter);
+ return QBenchmarkEvent::eventCounter;
+}
+
+// It's very tempting to simply reject a measurement if 0 events
+// where counted, however that is a possible situation and returning
+// false here will create a infinite loop. Do not change this.
+bool QBenchmarkEvent::isMeasurementAccepted(qint64 measurement)
+{
+ Q_UNUSED(measurement);
+ return true;
+}
+
+int QBenchmarkEvent::adjustIterationCount(int suggestion)
+{
+ return suggestion;
+}
+
+int QBenchmarkEvent::adjustMedianCount(int suggestion)
+{
+ Q_UNUSED(suggestion);
+ return 1;
+}
+
+QTest::QBenchmarkMetric QBenchmarkEvent::metricType()
+{
+ return QTest::Events;
+}
+
+// This could be done in a much better way, this is just the beginning.
+bool QBenchmarkEvent::eventCountingMechanism(void *message)
+{
+ Q_UNUSED(message);
+ QBenchmarkEvent::eventCounter++;
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qbenchmarkevent_p.h b/src/testlib/qbenchmarkevent_p.h
new file mode 100644
index 0000000000..62e54ba001
--- /dev/null
+++ b/src/testlib/qbenchmarkevent_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARKEVENT_P_H
+#define QBENCHMARKEVENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qbenchmarkmeasurement_p.h"
+#include <QAbstractEventDispatcher>
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QBenchmarkEvent : public QBenchmarkMeasurerBase
+{
+public:
+ ~QBenchmarkEvent();
+ void start();
+ qint64 checkpoint();
+ qint64 stop();
+ bool isMeasurementAccepted(qint64 measurement);
+ int adjustIterationCount(int suggestion);
+ int adjustMedianCount(int suggestion);
+ bool repeatCount() { return 1; }
+ QTest::QBenchmarkMetric metricType();
+ static bool eventCountingMechanism(void *message);
+ static qint64 eventCounter;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBENCHMARKEVENT_H
diff --git a/src/testlib/qbenchmarkmeasurement.cpp b/src/testlib/qbenchmarkmeasurement.cpp
new file mode 100644
index 0000000000..518d02384f
--- /dev/null
+++ b/src/testlib/qbenchmarkmeasurement.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qbenchmarkmeasurement_p.h"
+#include "QtTest/private/qbenchmark_p.h"
+#include "QtTest/private/qbenchmarkmetric_p.h"
+#include "qbenchmark.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+// QBenchmarkTimeMeasurer implementation
+
+void QBenchmarkTimeMeasurer::start()
+{
+ time.start();
+}
+
+qint64 QBenchmarkTimeMeasurer::checkpoint()
+{
+ return time.elapsed();
+}
+
+qint64 QBenchmarkTimeMeasurer::stop()
+{
+ return time.elapsed();
+}
+
+bool QBenchmarkTimeMeasurer::isMeasurementAccepted(qint64 measurement)
+{
+ return (measurement > 50);
+}
+
+int QBenchmarkTimeMeasurer::adjustIterationCount(int suggestion)
+{
+ return suggestion;
+}
+
+bool QBenchmarkTimeMeasurer::needsWarmupIteration()
+{
+ return true;
+}
+
+int QBenchmarkTimeMeasurer::adjustMedianCount(int)
+{
+ return 1;
+}
+
+QTest::QBenchmarkMetric QBenchmarkTimeMeasurer::metricType()
+{
+ return QTest::WalltimeMilliseconds;
+}
+
+#ifdef HAVE_TICK_COUNTER // defined in 3rdparty/cycle_p.h
+
+void QBenchmarkTickMeasurer::start()
+{
+ startTicks = getticks();
+}
+
+qint64 QBenchmarkTickMeasurer::checkpoint()
+{
+ CycleCounterTicks now = getticks();
+ return qRound64(elapsed(now, startTicks));
+}
+
+qint64 QBenchmarkTickMeasurer::stop()
+{
+ CycleCounterTicks now = getticks();
+ return qRound64(elapsed(now, startTicks));
+}
+
+bool QBenchmarkTickMeasurer::isMeasurementAccepted(qint64)
+{
+ return true;
+}
+
+int QBenchmarkTickMeasurer::adjustIterationCount(int)
+{
+ return 1;
+}
+
+int QBenchmarkTickMeasurer::adjustMedianCount(int)
+{
+ return 1;
+}
+
+bool QBenchmarkTickMeasurer::needsWarmupIteration()
+{
+ return true;
+}
+
+QTest::QBenchmarkMetric QBenchmarkTickMeasurer::metricType()
+{
+ return QTest::CPUTicks;
+}
+
+#endif
+
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qbenchmarkmeasurement_p.h b/src/testlib/qbenchmarkmeasurement_p.h
new file mode 100644
index 0000000000..12401b23ff
--- /dev/null
+++ b/src/testlib/qbenchmarkmeasurement_p.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARK_MEASUREMENT_P_H
+#define QBENCHMARK_MEASUREMENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qelapsedtimer.h>
+#include "3rdparty/cycle_p.h"
+#include "qbenchmark.h"
+
+QT_BEGIN_NAMESPACE
+
+class QBenchmarkMeasurerBase
+{
+public:
+ virtual ~QBenchmarkMeasurerBase(){};
+ virtual void init() {};
+ virtual void start() = 0;
+ virtual qint64 checkpoint() = 0;
+ virtual qint64 stop() = 0;
+ virtual bool isMeasurementAccepted(qint64 measurement) = 0;
+ virtual int adjustIterationCount(int suggestion) = 0;
+ virtual int adjustMedianCount(int suggestion) = 0;
+ virtual bool repeatCount() { return 1; }
+ virtual bool needsWarmupIteration() { return false; }
+ virtual QTest::QBenchmarkMetric metricType() = 0;
+};
+
+class QBenchmarkTimeMeasurer : public QBenchmarkMeasurerBase
+{
+public:
+ void start();
+ qint64 checkpoint();
+ qint64 stop();
+ bool isMeasurementAccepted(qint64 measurement);
+ int adjustIterationCount(int sugestion);
+ int adjustMedianCount(int suggestion);
+ bool needsWarmupIteration();
+ QTest::QBenchmarkMetric metricType();
+private:
+ QElapsedTimer time;
+};
+
+#ifdef HAVE_TICK_COUNTER // defined in 3rdparty/cycle_p.h
+
+class QBenchmarkTickMeasurer : public QBenchmarkMeasurerBase
+{
+public:
+ void start();
+ qint64 checkpoint();
+ qint64 stop();
+ bool isMeasurementAccepted(qint64 measurement);
+ int adjustIterationCount(int);
+ int adjustMedianCount(int suggestion);
+ bool needsWarmupIteration();
+ QTest::QBenchmarkMetric metricType();
+private:
+ CycleCounterTicks startTicks;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QBENCHMARK_MEASUREMENT_P_H
diff --git a/src/testlib/qbenchmarkmetric.cpp b/src/testlib/qbenchmarkmetric.cpp
new file mode 100644
index 0000000000..025bf4685c
--- /dev/null
+++ b/src/testlib/qbenchmarkmetric.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/private/qbenchmarkmetric_p.h>
+
+/*!
+ \enum QTest::QBenchmarkMetric
+ \since 4.7
+
+ This enum lists all the things that can be benchmarked.
+
+ \value FramesPerSecond Frames per second
+ \value BitsPerSecond Bits per second
+ \value BytesPerSecond Bytes per second
+ \value WalltimeMilliseconds Clock time in milliseconds
+ \value CPUTicks CPU time
+ \value InstructionReads Instruction reads
+ \value Events Event count
+
+ \sa QTest::benchmarkMetricName(), QTest::benchmarkMetricUnit()
+
+ */
+
+/*!
+ \relates QTest
+ \since 4.7
+ Returns the enum value \a metric as a character string.
+ */
+const char * QTest::benchmarkMetricName(QBenchmarkMetric metric)
+{
+ switch (metric) {
+ case FramesPerSecond:
+ return "FramesPerSecond";
+ case BitsPerSecond:
+ return "BitsPerSecond";
+ case BytesPerSecond:
+ return "BytesPerSecond";
+ case WalltimeMilliseconds:
+ return "WalltimeMilliseconds";
+ case CPUTicks:
+ return "CPUTicks";
+ case InstructionReads:
+ return "InstructionReads";
+ case Events:
+ return "Events";
+ default:
+ return "";
+ }
+};
+
+/*!
+ \relates QTest
+ \since 4.7
+ Retuns the units of measure for the specified \a metric.
+ */
+const char * QTest::benchmarkMetricUnit(QBenchmarkMetric metric)
+{
+ switch (metric) {
+ case FramesPerSecond:
+ return "fps";
+ case BitsPerSecond:
+ return "bits/s";
+ case BytesPerSecond:
+ return "bytes/s";
+ case WalltimeMilliseconds:
+ return "msecs";
+ case CPUTicks:
+ return "CPU ticks";
+ case InstructionReads:
+ return "instruction reads";
+ case Events:
+ return "events";
+ default:
+ return "";
+ }
+}
+
diff --git a/src/testlib/qbenchmarkmetric.h b/src/testlib/qbenchmarkmetric.h
new file mode 100644
index 0000000000..c8ab2fd5af
--- /dev/null
+++ b/src/testlib/qbenchmarkmetric.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARKMETRIC_H
+#define QBENCHMARKMETRIC_H
+
+#include <QtTest/qtest_global.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest {
+
+enum QBenchmarkMetric {
+ FramesPerSecond,
+ BitsPerSecond,
+ BytesPerSecond,
+ WalltimeMilliseconds,
+ CPUTicks,
+ InstructionReads,
+ Events
+};
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QBENCHMARK_H
diff --git a/src/testlib/qbenchmarkmetric_p.h b/src/testlib/qbenchmarkmetric_p.h
new file mode 100644
index 0000000000..14a35e95ee
--- /dev/null
+++ b/src/testlib/qbenchmarkmetric_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARKMETRIC_P_H
+#define QBENCHMARKMETRIC_P_H
+
+#include <QtTest/qtest_global.h>
+#include <QtTest/qbenchmarkmetric.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest {
+ const char * benchmarkMetricName(QBenchmarkMetric metric);
+ const char * benchmarkMetricUnit(QBenchmarkMetric metric);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QBENCHMARK_H
diff --git a/src/testlib/qbenchmarkvalgrind.cpp b/src/testlib/qbenchmarkvalgrind.cpp
new file mode 100644
index 0000000000..dc34001b1d
--- /dev/null
+++ b/src/testlib/qbenchmarkvalgrind.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qbenchmark_p.h"
+
+#ifdef QTESTLIB_USE_VALGRIND
+
+#include "QtTest/private/qbenchmarkvalgrind_p.h"
+#include <QtCore/qstringlist.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qprocess.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qset.h>
+#include "3rdparty/callgrind_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// Returns true iff a sufficiently recent valgrind is available.
+bool QBenchmarkValgrindUtils::haveValgrind()
+{
+#ifdef NVALGRIND
+ return false;
+#else
+ QProcess process;
+ QStringList args;
+ args << QLatin1String("--version");
+ process.start(QLatin1String("valgrind"), args);
+ if (!process.waitForFinished(-1))
+ return false;
+ const QByteArray out = process.readAllStandardOutput();
+ const QRegExp rx(QLatin1String("^valgrind-([0-9]).([0-9]).[0-9]"));
+ if (rx.indexIn(QLatin1String(out.data())) == -1)
+ return false;
+ bool ok;
+ const int major = rx.cap(1).toInt(&ok);
+ if (!ok)
+ return false;
+ const int minor = rx.cap(2).toInt(&ok);
+ if (!ok)
+ return false;
+// return (major > 3 || (major == 3 && minor >= 3)); // v >= 3.3 for --callgrind-out-file option
+ Q_UNUSED(major);
+ Q_UNUSED(minor);
+ return true; // skip version restriction for now
+#endif
+}
+
+// Reruns this program through callgrind.
+// Returns true upon success, otherwise false.
+bool QBenchmarkValgrindUtils::rerunThroughCallgrind(const QStringList &origAppArgs, int &exitCode)
+{
+ if (!QBenchmarkValgrindUtils::runCallgrindSubProcess(origAppArgs, exitCode)) {
+ qWarning("failed to run callgrind subprocess");
+ return false;
+ }
+ return true;
+}
+
+static void dumpOutput(const QByteArray &data, FILE *fh)
+{
+ QFile file;
+ file.open(fh, QIODevice::WriteOnly);
+ file.write(data);
+}
+
+qint64 QBenchmarkValgrindUtils::extractResult(const QString &fileName)
+{
+ QFile file(fileName);
+ const bool openOk = file.open(QIODevice::ReadOnly | QIODevice::Text);
+ Q_ASSERT(openOk);
+ Q_UNUSED(openOk);
+
+ qint64 val = -1;
+ bool valSeen = false;
+ const QRegExp rxValue(QLatin1String("^summary: (\\d+)"));
+ while (!file.atEnd()) {
+ const QString line(QLatin1String(file.readLine()));
+ if (rxValue.indexIn(line) != -1) {
+ Q_ASSERT(rxValue.captureCount() == 1);
+ bool ok;
+ val = rxValue.cap(1).toLongLong(&ok);
+ Q_ASSERT(ok);
+ valSeen = true;
+ break;
+ }
+ }
+ Q_ASSERT(valSeen);
+ return val;
+}
+
+// Gets the newest file name (i.e. the one with the highest integer suffix).
+QString QBenchmarkValgrindUtils::getNewestFileName()
+{
+ QStringList nameFilters;
+ QString base = QBenchmarkGlobalData::current->callgrindOutFileBase;
+ Q_ASSERT(!base.isEmpty());
+
+ nameFilters << QString::fromLatin1("%1.*").arg(base);
+ QFileInfoList fiList = QDir().entryInfoList(nameFilters, QDir::Files | QDir::Readable);
+ Q_ASSERT(!fiList.empty());
+ int hiSuffix = -1;
+ QFileInfo lastFileInfo;
+ const QString pattern = QString::fromLatin1("%1.(\\d+)").arg(base);
+ const QRegExp rx(pattern);
+ foreach (QFileInfo fileInfo, fiList) {
+ const int index = rx.indexIn(fileInfo.fileName());
+ Q_ASSERT(index == 0);
+ Q_UNUSED(index);
+ bool ok;
+ const int suffix = rx.cap(1).toInt(&ok);
+ Q_ASSERT(ok);
+ Q_ASSERT(suffix >= 0);
+ if (suffix > hiSuffix) {
+ lastFileInfo = fileInfo;
+ hiSuffix = suffix;
+ }
+ }
+
+ return lastFileInfo.fileName();
+}
+
+qint64 QBenchmarkValgrindUtils::extractLastResult()
+{
+ return extractResult(getNewestFileName());
+}
+
+void QBenchmarkValgrindUtils::cleanup()
+{
+ QStringList nameFilters;
+ QString base = QBenchmarkGlobalData::current->callgrindOutFileBase;
+ Q_ASSERT(!base.isEmpty());
+ nameFilters
+ << base // overall summary
+ << QString::fromLatin1("%1.*").arg(base); // individual dumps
+ QFileInfoList fiList = QDir().entryInfoList(nameFilters, QDir::Files | QDir::Readable);
+ foreach (QFileInfo fileInfo, fiList) {
+ const bool removeOk = QFile::remove(fileInfo.fileName());
+ Q_ASSERT(removeOk);
+ Q_UNUSED(removeOk);
+ }
+}
+
+QString QBenchmarkValgrindUtils::outFileBase(qint64 pid)
+{
+ return QString::fromLatin1("callgrind.out.%1").arg(
+ pid != -1 ? pid : QCoreApplication::applicationPid());
+}
+
+// Reruns this program through callgrind, storing callgrind result files in the
+// current directory.
+// Returns true upon success, otherwise false.
+bool QBenchmarkValgrindUtils::runCallgrindSubProcess(const QStringList &origAppArgs, int &exitCode)
+{
+ const QString execFile(origAppArgs.at(0));
+ QStringList args;
+ args << QLatin1String("--tool=callgrind") << QLatin1String("--instr-atstart=yes")
+ << QLatin1String("--quiet")
+ << execFile << QLatin1String("-callgrindchild");
+
+#if (defined Q_WS_QWS)
+ // While running the child process, we aren't processing events, and hence aren't
+ // acting as the QWS server. Therefore it's necessary to tell the child to act
+ // as its own server instead of connecting to us.
+ args << QLatin1String("-qws");
+#endif
+
+ // pass on original arguments that make sense (e.g. avoid wasting time producing output
+ // that will be ignored anyway) ...
+ for (int i = 1; i < origAppArgs.size(); ++i) {
+ const QString arg(origAppArgs.at(i));
+ if (arg == QLatin1String("-callgrind"))
+ continue;
+ args << arg; // ok to pass on
+ }
+
+ QProcess process;
+ process.start(QLatin1String("valgrind"), args);
+ process.waitForStarted(-1);
+ QBenchmarkGlobalData::current->callgrindOutFileBase =
+ QBenchmarkValgrindUtils::outFileBase(process.pid());
+ const bool finishedOk = process.waitForFinished(-1);
+ exitCode = process.exitCode();
+
+ dumpOutput(process.readAllStandardOutput(), stdout);
+ dumpOutput(process.readAllStandardError(), stderr);
+
+ return finishedOk;
+}
+
+void QBenchmarkCallgrindMeasurer::start()
+{
+ CALLGRIND_ZERO_STATS;
+}
+
+qint64 QBenchmarkCallgrindMeasurer::checkpoint()
+{
+ CALLGRIND_DUMP_STATS;
+ const qint64 result = QBenchmarkValgrindUtils::extractLastResult();
+ return result;
+}
+
+qint64 QBenchmarkCallgrindMeasurer::stop()
+{
+ return checkpoint();
+}
+
+bool QBenchmarkCallgrindMeasurer::isMeasurementAccepted(qint64 measurement)
+{
+ Q_UNUSED(measurement);
+ return true;
+}
+
+int QBenchmarkCallgrindMeasurer::adjustIterationCount(int)
+{
+ return 1;
+}
+
+int QBenchmarkCallgrindMeasurer::adjustMedianCount(int)
+{
+ return 1;
+}
+
+bool QBenchmarkCallgrindMeasurer::needsWarmupIteration()
+{
+ return true;
+}
+
+QTest::QBenchmarkMetric QBenchmarkCallgrindMeasurer::metricType()
+{
+ return QTest::InstructionReads;
+}
+
+QT_END_NAMESPACE
+
+#endif // QTESTLIB_USE_VALGRIND
diff --git a/src/testlib/qbenchmarkvalgrind_p.h b/src/testlib/qbenchmarkvalgrind_p.h
new file mode 100644
index 0000000000..922f64cc6c
--- /dev/null
+++ b/src/testlib/qbenchmarkvalgrind_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARKVALGRIND_P_H
+#define QBENCHMARKVALGRIND_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtTest/private/qbenchmarkmeasurement_p.h"
+#include "QtTest/private/qbenchmarkmetric_p.h"
+#include <QtCore/qmap.h>
+#include <QtCore/qstring.h>
+
+class QStringList;
+
+QT_BEGIN_NAMESPACE
+
+class QBenchmarkValgrindUtils
+{
+public:
+ static bool haveValgrind();
+ static bool rerunThroughCallgrind(const QStringList &origAppArgs, int &exitCode);
+ static bool runCallgrindSubProcess(const QStringList &origAppArgs, int &exitCode);
+ static qint64 extractResult(const QString &fileName);
+ static QString getNewestFileName();
+ static qint64 extractLastResult();
+ static void cleanup();
+ static QString outFileBase(qint64 pid = -1);
+};
+
+class QBenchmarkCallgrindMeasurer : public QBenchmarkMeasurerBase
+{
+public:
+ void start();
+ qint64 checkpoint();
+ qint64 stop();
+ bool isMeasurementAccepted(qint64 measurement);
+ int adjustIterationCount(int);
+ int adjustMedianCount(int);
+ bool needsWarmupIteration();
+ QTest::QBenchmarkMetric metricType();
+};
+
+QT_END_NAMESPACE
+
+#endif // QBENCHMARKVALGRIND_H
diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp
new file mode 100644
index 0000000000..e1ae534970
--- /dev/null
+++ b/src/testlib/qplaintestlogger.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qtestresult_p.h"
+#include "QtTest/qtestassert.h"
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/private/qplaintestlogger_p.h"
+#include "QtTest/private/qbenchmark_p.h"
+#include "QtTest/private/qbenchmarkmetric_p.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef Q_OS_WIN
+#include "windows.h"
+#endif
+
+#if defined(Q_OS_SYMBIAN)
+#include <e32debug.h>
+#endif
+
+#ifdef Q_OS_WINCE
+#include <QtCore/QString>
+#endif
+
+#include <QtCore/QByteArray>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest {
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+
+ static CRITICAL_SECTION outputCriticalSection;
+ static HANDLE hConsole = INVALID_HANDLE_VALUE;
+ static WORD consoleAttributes = 0;
+
+ static const char *qWinColoredMsg(int prefix, int color, const char *msg)
+ {
+ if (!hConsole)
+ return msg;
+
+ WORD attr = consoleAttributes & ~(FOREGROUND_GREEN | FOREGROUND_BLUE
+ | FOREGROUND_RED | FOREGROUND_INTENSITY);
+ if (prefix)
+ attr |= FOREGROUND_INTENSITY;
+ if (color == 32)
+ attr |= FOREGROUND_GREEN;
+ if (color == 36)
+ attr |= FOREGROUND_BLUE | FOREGROUND_GREEN;
+ if (color == 31)
+ attr |= FOREGROUND_RED | FOREGROUND_INTENSITY;
+ if (color == 37)
+ attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+ if (color == 33)
+ attr |= FOREGROUND_RED | FOREGROUND_GREEN;
+ SetConsoleTextAttribute(hConsole, attr);
+ printf(msg);
+ SetConsoleTextAttribute(hConsole, consoleAttributes);
+ return "";
+ }
+
+# define COLORED_MSG(prefix, color, msg) colored ? qWinColoredMsg(prefix, color, msg) : msg
+#else
+# define COLORED_MSG(prefix, color, msg) colored && QAbstractTestLogger::isTtyOutput() ? "\033["#prefix";"#color"m" msg "\033[0m" : msg
+#endif
+
+ static const char *incidentType2String(QAbstractTestLogger::IncidentTypes type)
+ {
+ static bool colored = (!qgetenv("QTEST_COLORED").isEmpty());
+ switch (type) {
+ case QAbstractTestLogger::Pass:
+ return COLORED_MSG(0, 32, "PASS "); //green
+ case QAbstractTestLogger::XFail:
+ return COLORED_MSG(1, 32, "XFAIL "); //light green
+ case QAbstractTestLogger::Fail:
+ return COLORED_MSG(0, 31, "FAIL! "); //red
+ case QAbstractTestLogger::XPass:
+ return COLORED_MSG(0, 31, "XPASS "); //red, too
+ }
+ return "??????";
+ }
+
+ static const char *benchmarkResult2String()
+ {
+ static bool colored = (!qgetenv("QTEST_COLORED").isEmpty());
+ return COLORED_MSG(0, 36, "RESULT "); // cyan
+ }
+
+ static const char *messageType2String(QAbstractTestLogger::MessageTypes type)
+ {
+#ifdef Q_OS_WIN
+ static bool colored = (!qgetenv("QTEST_COLORED").isEmpty());
+#else
+ static bool colored = ::getenv("QTEST_COLORED");
+#endif
+ switch (type) {
+ case QAbstractTestLogger::Skip:
+ return COLORED_MSG(0, 37, "SKIP "); //white
+ case QAbstractTestLogger::Warn:
+ return COLORED_MSG(0, 33, "WARNING"); // yellow
+ case QAbstractTestLogger::QWarning:
+ return COLORED_MSG(1, 33, "QWARN ");
+ case QAbstractTestLogger::QDebug:
+ return COLORED_MSG(1, 33, "QDEBUG ");
+ case QAbstractTestLogger::QSystem:
+ return COLORED_MSG(1, 33, "QSYSTEM");
+ case QAbstractTestLogger::QFatal:
+ return COLORED_MSG(0, 31, "QFATAL "); // red
+ case QAbstractTestLogger::Info:
+ return "INFO "; // no coloring
+ }
+ 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)
+ {
+ if (num <= 0)
+ return 0;
+
+ int digits = 0;
+ qreal divisor = 1;
+
+ while (num / divisor >= 1) {
+ divisor *= 10;
+ ++digits;
+ }
+
+ return digits;
+ }
+
+ // Pretty-prints a benchmark result using the given number of digits.
+ template <typename T> QString formatResult(T number, int significantDigits)
+ {
+ if (number < T(0))
+ return QLatin1String("NAN");
+ if (number == T(0))
+ return QLatin1String("0");
+
+ QString beforeDecimalPoint = QString::number(qint64(number), 'f', 0);
+ QString afterDecimalPoint = QString::number(number, 'f', 20);
+ afterDecimalPoint.remove(0, beforeDecimalPoint.count() + 1);
+
+ int beforeUse = qMin(beforeDecimalPoint.count(), significantDigits);
+ int beforeRemove = beforeDecimalPoint.count() - beforeUse;
+
+ // Replace insignificant digits before the decimal point with zeros.
+ beforeDecimalPoint.chop(beforeRemove);
+ for (int i = 0; i < beforeRemove; ++i) {
+ beforeDecimalPoint.append(QLatin1Char('0'));
+ }
+
+ int afterUse = significantDigits - beforeUse;
+
+ // leading zeroes after the decimal point does not count towards the digit use.
+ if (beforeDecimalPoint == QLatin1String("0") && afterDecimalPoint.isEmpty() == false) {
+ ++afterUse;
+
+ int i = 0;
+ while (i < afterDecimalPoint.count() && afterDecimalPoint.at(i) == QLatin1Char('0')) {
+ ++i;
+ }
+
+ afterUse += i;
+ }
+
+ int afterRemove = afterDecimalPoint.count() - afterUse;
+ afterDecimalPoint.chop(afterRemove);
+
+ QChar separator = QLatin1Char(',');
+ QChar decimalPoint = QLatin1Char('.');
+
+ // insert thousands separators
+ int length = beforeDecimalPoint.length();
+ for (int i = beforeDecimalPoint.length() -1; i >= 1; --i) {
+ if ((length - i) % 3 == 0)
+ beforeDecimalPoint.insert(i, separator);
+ }
+
+ QString print;
+ print = beforeDecimalPoint;
+ if (afterUse > 0)
+ print.append(decimalPoint);
+
+ print += afterDecimalPoint;
+
+
+ return print;
+ }
+
+ template <typename T>
+ int formatResult(char * buffer, int bufferSize, T number, int significantDigits)
+ {
+ QString result = formatResult(number, significantDigits);
+ qstrncpy(buffer, result.toAscii().constData(), bufferSize);
+ 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());
+ }
+
+
+ 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);
+ }
+}
+
+QPlainTestLogger::QPlainTestLogger()
+: randomSeed(9), hasRandomSeed(false)
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ InitializeCriticalSection(&QTest::outputCriticalSection);
+ QTest::hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (QTest::hConsole != INVALID_HANDLE_VALUE) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo(QTest::hConsole, &info)) {
+ QTest::consoleAttributes = info.wAttributes;
+ } else {
+ QTest::hConsole = INVALID_HANDLE_VALUE;
+ }
+ }
+#endif
+}
+
+QPlainTestLogger::~QPlainTestLogger()
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ DeleteCriticalSection(&QTest::outputCriticalSection);
+#endif
+}
+
+void QPlainTestLogger::startLogging()
+{
+ QAbstractTestLogger::startLogging();
+
+ char buf[1024];
+ if (QTestLog::verboseLevel() < 0) {
+ QTest::qt_snprintf(buf, sizeof(buf), "Testing %s\n",
+ QTestResult::currentTestObjectName());
+ } else {
+ if (hasRandomSeed) {
+ QTest::qt_snprintf(buf, sizeof(buf),
+ "********* Start testing of %s *********\n"
+ "Config: Using QTest library " QTEST_VERSION_STR
+ ", Qt %s, Random seed %d\n", QTestResult::currentTestObjectName(), qVersion(), randomSeed);
+ } else {
+ QTest::qt_snprintf(buf, sizeof(buf),
+ "********* Start testing of %s *********\n"
+ "Config: Using QTest library " QTEST_VERSION_STR
+ ", Qt %s\n", QTestResult::currentTestObjectName(), qVersion());
+ }
+ }
+ QTest::outputMessage(buf);
+}
+
+void QPlainTestLogger::stopLogging()
+{
+ char buf[1024];
+ if (QTestLog::verboseLevel() < 0) {
+ QTest::qt_snprintf(buf, sizeof(buf), "Totals: %d passed, %d failed, %d skipped\n",
+ QTestResult::passCount(), QTestResult::failCount(),
+ QTestResult::skipCount());
+ } else {
+ QTest::qt_snprintf(buf, sizeof(buf),
+ "Totals: %d passed, %d failed, %d skipped\n"
+ "********* Finished testing of %s *********\n",
+ QTestResult::passCount(), QTestResult::failCount(),
+ QTestResult::skipCount(), QTestResult::currentTestObjectName());
+ }
+ QTest::outputMessage(buf);
+
+ QAbstractTestLogger::stopLogging();
+}
+
+
+void QPlainTestLogger::enterTestFunction(const char * /*function*/)
+{
+ if (QTestLog::verboseLevel() >= 1)
+ QTest::printMessage(QTest::messageType2String(Info), "entering");
+}
+
+void QPlainTestLogger::leaveTestFunction()
+{
+}
+
+void QPlainTestLogger::addIncident(IncidentTypes type, const char *description,
+ const char *file, int line)
+{
+ // suppress PASS in silent mode
+ if (type == QAbstractTestLogger::Pass && QTestLog::verboseLevel() < 0)
+ return;
+
+ QTest::printMessage(QTest::incidentType2String(type), description, file, line);
+}
+
+void QPlainTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
+{
+// QTest::printBenchmarkResult(QTest::benchmarkResult2String(), value, iterations);
+ QTest::printBenchmarkResult(result);
+}
+
+void QPlainTestLogger::addMessage(MessageTypes type, const char *message,
+ const char *file, int line)
+{
+ // suppress PASS in silent mode
+ if ((type == QAbstractTestLogger::Skip || type == QAbstractTestLogger::Info)
+ && QTestLog::verboseLevel() < 0)
+ return;
+
+ QTest::printMessage(QTest::messageType2String(type), message, file, line);
+}
+
+void QPlainTestLogger::registerRandomSeed(unsigned int seed)
+{
+ randomSeed = seed;
+ hasRandomSeed = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qplaintestlogger_p.h b/src/testlib/qplaintestlogger_p.h
new file mode 100644
index 0000000000..054ec1e152
--- /dev/null
+++ b/src/testlib/qplaintestlogger_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLAINTESTLOGGER_P_H
+#define QPLAINTESTLOGGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtTest/private/qabstracttestlogger_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlainTestLogger : public QAbstractTestLogger
+{
+public:
+ QPlainTestLogger();
+ ~QPlainTestLogger();
+
+ void startLogging();
+ void stopLogging();
+
+ void enterTestFunction(const char *function);
+ void leaveTestFunction();
+
+ void addIncident(IncidentTypes type, const char *description,
+ const char *file = 0, int line = 0);
+ void addBenchmarkResult(const QBenchmarkResult &result);
+
+ void addMessage(MessageTypes type, const char *message,
+ const char *file = 0, int line = 0);
+ void registerRandomSeed(unsigned int seed);
+private:
+ unsigned int randomSeed;
+ bool hasRandomSeed;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qsignaldumper.cpp b/src/testlib/qsignaldumper.cpp
new file mode 100644
index 0000000000..a574e31e38
--- /dev/null
+++ b/src/testlib/qsignaldumper.cpp
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qsignaldumper_p.h"
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+
+#include "QtTest/private/qtestlog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest
+{
+
+inline static void qPrintMessage(const QByteArray &ba)
+{
+ QTestLog::info(ba.constData(), 0, 0);
+}
+
+Q_GLOBAL_STATIC(QList<QByteArray>, ignoreClasses)
+static int iLevel = 0;
+static int ignoreLevel = 0;
+enum { IndentSpacesCount = 4 };
+
+static QByteArray memberName(const QMetaMethod &member)
+{
+ QByteArray ba = member.signature();
+ return ba.left(ba.indexOf('('));
+}
+
+static void qSignalDumperCallback(QObject *caller, int method_index, void **argv)
+{
+ Q_ASSERT(caller); Q_ASSERT(argv); Q_UNUSED(argv);
+ const QMetaObject *mo = caller->metaObject();
+ Q_ASSERT(mo);
+ QMetaMethod member = mo->method(method_index);
+ Q_ASSERT(member.signature());
+
+ if (QTest::ignoreClasses() && QTest::ignoreClasses()->contains(mo->className())) {
+ ++QTest::ignoreLevel;
+ return;
+ }
+
+ QByteArray str;
+ str.fill(' ', QTest::iLevel++ * QTest::IndentSpacesCount);
+ str += "Signal: ";
+ str += mo->className();
+ str += '(';
+
+ QString objname = caller->objectName();
+ str += objname.toLocal8Bit();
+ if (!objname.isEmpty())
+ str += ' ';
+ str += QByteArray::number(quintptr(caller), 16);
+
+ str += ") ";
+ str += QTest::memberName(member);
+ str += " (";
+
+ QList<QByteArray> args = member.parameterTypes();
+ for (int i = 0; i < args.count(); ++i) {
+ const QByteArray &arg = args.at(i);
+ int typeId = QMetaType::type(args.at(i).constData());
+ if (arg.endsWith('*') || arg.endsWith('&')) {
+ str += '(';
+ str += arg;
+ str += ')';
+ if (arg.endsWith('&'))
+ str += '@';
+
+ quintptr addr = quintptr(*reinterpret_cast<void **>(argv[i + 1]));
+ str.append(QByteArray::number(addr, 16));
+ } else if (typeId != QMetaType::Void) {
+ str.append(arg)
+ .append('(')
+ .append(QVariant(typeId, argv[i + 1]).toString().toLocal8Bit())
+ .append(')');
+ }
+ str.append(", ");
+ }
+ if (str.endsWith(", "))
+ str.chop(2);
+ str.append(')');
+ qPrintMessage(str);
+}
+
+static void qSignalDumperCallbackSlot(QObject *caller, int method_index, void **argv)
+{
+ Q_ASSERT(caller); Q_ASSERT(argv); Q_UNUSED(argv);
+ const QMetaObject *mo = caller->metaObject();
+ Q_ASSERT(mo);
+ QMetaMethod member = mo->method(method_index);
+ if (!member.signature())
+ return;
+
+ if (QTest::ignoreLevel ||
+ (QTest::ignoreClasses() && QTest::ignoreClasses()->contains(mo->className())))
+ return;
+
+ QByteArray str;
+ str.fill(' ', QTest::iLevel * QTest::IndentSpacesCount);
+ str += "Slot: ";
+ str += mo->className();
+ str += '(';
+
+ QString objname = caller->objectName();
+ str += objname.toLocal8Bit();
+ if (!objname.isEmpty())
+ str += ' ';
+ str += QByteArray::number(quintptr(caller), 16);
+
+ str += ") ";
+ str += member.signature();
+ qPrintMessage(str);
+}
+
+static void qSignalDumperCallbackEndSignal(QObject *caller, int /*method_index*/)
+{
+ Q_ASSERT(caller); Q_ASSERT(caller->metaObject());
+ if (QTest::ignoreClasses()
+ && QTest::ignoreClasses()->contains(caller->metaObject()->className())) {
+ --QTest::ignoreLevel;
+ Q_ASSERT(QTest::ignoreLevel >= 0);
+ return;
+ }
+ --QTest::iLevel;
+ Q_ASSERT(QTest::iLevel >= 0);
+}
+
+}
+
+// this struct is copied from qobject_p.h to prevent us
+// from including private Qt headers.
+struct QSignalSpyCallbackSet
+{
+ typedef void (*BeginCallback)(QObject *caller, int method_index, void **argv);
+ typedef void (*EndCallback)(QObject *caller, int method_index);
+ BeginCallback signal_begin_callback,
+ slot_begin_callback;
+ EndCallback signal_end_callback,
+ slot_end_callback;
+};
+extern void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &);
+
+void QSignalDumper::startDump()
+{
+ static QSignalSpyCallbackSet set = { QTest::qSignalDumperCallback,
+ QTest::qSignalDumperCallbackSlot, QTest::qSignalDumperCallbackEndSignal, 0 };
+ qt_register_signal_spy_callbacks(set);
+}
+
+void QSignalDumper::endDump()
+{
+ static QSignalSpyCallbackSet nset = { 0, 0, 0 ,0 };
+ qt_register_signal_spy_callbacks(nset);
+}
+
+void QSignalDumper::ignoreClass(const QByteArray &klass)
+{
+ if (QTest::ignoreClasses())
+ QTest::ignoreClasses()->append(klass);
+}
+
+void QSignalDumper::clearIgnoredClasses()
+{
+ if (QTest::ignoreClasses())
+ QTest::ignoreClasses()->clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qsignaldumper_p.h b/src/testlib/qsignaldumper_p.h
new file mode 100644
index 0000000000..6ba469bd49
--- /dev/null
+++ b/src/testlib/qsignaldumper_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALDUMPER_P_H
+#define QSIGNALDUMPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+
+class QSignalDumper
+{
+public:
+ static void startDump();
+ static void endDump();
+
+ static void ignoreClass(const QByteArray &klass);
+ static void clearIgnoredClasses();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qsignalspy.h b/src/testlib/qsignalspy.h
new file mode 100644
index 0000000000..b0b48c5025
--- /dev/null
+++ b/src/testlib/qsignalspy.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALSPY_H
+#define QSIGNALSPY_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QVariant;
+
+/* ### Qt5: change the class to use regular BC mechanisms, such that we can
+ * implement things like suggested in task 160192. */
+class QSignalSpy: public QObject, public QList<QList<QVariant> >
+{
+public:
+ QSignalSpy(QObject *obj, const char *aSignal)
+ {
+#ifdef Q_CC_BOR
+ const int memberOffset = QObject::staticMetaObject.methodCount();
+#else
+ static const int memberOffset = QObject::staticMetaObject.methodCount();
+#endif
+ Q_ASSERT(obj);
+ Q_ASSERT(aSignal);
+
+ if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
+ qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
+ return;
+ }
+
+ QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
+ const QMetaObject *mo = obj->metaObject();
+ int sigIndex = mo->indexOfMethod(ba.constData());
+ if (sigIndex < 0) {
+ qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
+ return;
+ }
+
+ if (!QMetaObject::connect(obj, sigIndex, this, memberOffset,
+ Qt::DirectConnection, 0)) {
+ qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
+ return;
+ }
+ sig = ba;
+ initArgs(mo->method(sigIndex));
+ }
+
+ inline bool isValid() const { return !sig.isEmpty(); }
+ inline QByteArray signal() const { return sig; }
+
+
+ int qt_metacall(QMetaObject::Call call, int methodId, void **a)
+ {
+ methodId = QObject::qt_metacall(call, methodId, a);
+ if (methodId < 0)
+ return methodId;
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ if (methodId == 0) {
+ appendArgs(a);
+ }
+ --methodId;
+ }
+ return methodId;
+ }
+
+private:
+ void initArgs(const QMetaMethod &member)
+ {
+ QList<QByteArray> params = member.parameterTypes();
+ for (int i = 0; i < params.count(); ++i) {
+ int tp = QMetaType::type(params.at(i).constData());
+ if (tp == QMetaType::Void)
+ qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.",
+ params.at(i).constData());
+ args << tp;
+ }
+ }
+
+ void appendArgs(void **a)
+ {
+ QList<QVariant> list;
+ for (int i = 0; i < args.count(); ++i) {
+ QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
+ list << QVariant(type, a[i + 1]);
+ }
+ append(list);
+ }
+
+ // the full, normalized signal name
+ QByteArray sig;
+ // holds the QMetaType types for the argument list of the signal
+ QList<int> args;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qsignalspy.qdoc b/src/testlib/qsignalspy.qdoc
new file mode 100644
index 0000000000..0c22868852
--- /dev/null
+++ b/src/testlib/qsignalspy.qdoc
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QSignalSpy
+ \inmodule QtTest
+
+ \brief The QSignalSpy class enables introspection of signal emission.
+
+ QSignalSpy can connect to any signal of any object and records its emission.
+ QSignalSpy itself is a list of QVariant lists. Each emission of the signal
+ will append one item to the list, containing the arguments of the signal.
+
+ The following example records all signal emissions for the \c clicked() signal
+ of a QCheckBox:
+
+ \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 0
+
+ \c{spy.takeFirst()} returns the arguments for the first emitted signal, as a
+ list of QVariant objects. The \c clicked() signal has a single bool argument,
+ which is stored as the first entry in the list of arguments.
+
+ The example below catches a signal from a custom object:
+
+ \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 1
+
+ \bold {Note:} Non-standard data types need to be registered, using
+ the qRegisterMetaType() function, before you can create a
+ QSignalSpy. For example:
+
+ \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 2
+
+ To retrieve the \c QModelIndex, you can use qvariant_cast:
+
+ \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 3
+ */
+
+/*! \fn QSignalSpy::QSignalSpy(QObject *object, const char *signal)
+
+ Constructs a new QSignalSpy that listens for emissions of the \a signal
+ from the QObject \a object. Neither \a signal nor \a object can be null.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 4
+*/
+
+/*! \fn QSignalSpy::isValid() const
+
+ Returns true if the signal spy listens to a valid signal, otherwise false.
+*/
+
+/*! \fn QSignalSpy::signal() const
+
+ Returns the normalized signal the spy is currently listening to.
+*/
+
+/*! \fn int QSignalSpy::qt_metacall(QMetaObject::Call call, int id, void **a)
+ \internal
+*/
+
diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h
new file mode 100644
index 0000000000..36521090d5
--- /dev/null
+++ b/src/testlib/qtest.h
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEST_H
+#define QTEST_H
+
+#include <QtTest/qtest_global.h>
+#include <QtTest/qtestcase.h>
+#include <QtTest/qtestdata.h>
+#include <QtTest/qtestdata.h>
+#include <QtTest/qbenchmark.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qurl.h>
+
+#include <QtCore/qpoint.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qrect.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest
+{
+
+template<> inline char *toString(const QLatin1String &str)
+{
+ return qstrdup(str.latin1());
+}
+
+template<> inline char *toString(const QString &str)
+{
+ return qstrdup(str.toLatin1().constData());
+}
+
+template<> inline char *toString(const QByteArray &ba)
+{
+ return QTest::toHexRepresentation(ba.constData(), ba.length());
+}
+
+template<> inline char *toString(const QTime &time)
+{
+ return time.isValid()
+ ? qstrdup(time.toString(QLatin1String("hh:mm:ss.zzz")).toLatin1().constData())
+ : qstrdup("Invalid QTime");
+}
+
+template<> inline char *toString(const QDate &date)
+{
+ return date.isValid()
+ ? qstrdup(date.toString(QLatin1String("yyyy/MM/dd")).toLatin1().constData())
+ : qstrdup("Invalid QDate");
+}
+
+template<> inline char *toString(const QDateTime &dateTime)
+{
+ return dateTime.isValid()
+ ? qstrdup((dateTime.toString(QLatin1String("yyyy/MM/dd hh:mm:ss.zzz")) +
+ (dateTime.timeSpec() == Qt::LocalTime ? QLatin1String("[local time]") : QLatin1String("[UTC]"))).toLatin1().constData())
+ : qstrdup("Invalid QDateTime");
+}
+
+template<> inline char *toString(const QChar &c)
+{
+ return qstrdup(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16)).toLatin1().constData());
+}
+
+template<> inline char *toString(const QPoint &p)
+{
+ return qstrdup(QString::fromLatin1("QPoint(%1,%2)").arg(p.x()).arg(p.y()).toLatin1().constData());
+}
+
+template<> inline char *toString(const QSize &s)
+{
+ return qstrdup(QString::fromLatin1("QSize(%1x%2)").arg(s.width()).arg(s.height()).toLatin1().constData());
+}
+
+template<> inline char *toString(const QRect &s)
+{
+ return qstrdup(QString::fromLatin1("QRect(%1,%2 %5x%6) (bottomright %3,%4)").arg(s.left()).arg(s.top()).arg(s.right()).arg(s.bottom()).arg(s.width()).arg(s.height()).toLatin1().constData());
+}
+
+template<> inline char *toString(const QPointF &p)
+{
+ return qstrdup(QString::fromLatin1("QPointF(%1,%2)").arg(p.x()).arg(p.y()).toLatin1().constData());
+}
+
+template<> inline char *toString(const QSizeF &s)
+{
+ return qstrdup(QString::fromLatin1("QSizeF(%1x%2)").arg(s.width()).arg(s.height()).toLatin1().constData());
+}
+
+template<> inline char *toString(const QRectF &s)
+{
+ return qstrdup(QString::fromLatin1("QRectF(%1,%2 %5x%6) (bottomright %3,%4)").arg(s.left()).arg(s.top()).arg(s.right()).arg(s.bottom()).arg(s.width()).arg(s.height()).toLatin1().constData());
+}
+
+template<> inline char *toString(const QUrl &uri)
+{
+ return qstrdup(uri.toEncoded().constData());
+}
+
+template<> inline char *toString(const QVariant &v)
+{
+ QByteArray vstring("QVariant(");
+ if (v.isValid()) {
+ QByteArray type(v.typeName());
+ if (type.isEmpty()) {
+ type = QByteArray::number(v.userType());
+ }
+ vstring.append(type);
+ if (!v.isNull()) {
+ vstring.append(',');
+ if (v.canConvert(QVariant::String)) {
+ vstring.append(qvariant_cast<QString>(v).toLatin1());
+ }
+ else {
+ vstring.append("<value not representable as string>");
+ }
+ }
+ }
+ vstring.append(')');
+
+ return qstrdup(vstring.constData());
+}
+
+#ifndef QTEST_NO_SPECIALIZATIONS
+template<>
+#endif
+inline bool qCompare(QString const &t1, QLatin1String const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+{
+ return qCompare<QString>(t1, QString(t2), actual, expected, file, line);
+}
+#ifndef QTEST_NO_SPECIALIZATIONS
+template<>
+#endif
+inline bool qCompare(QLatin1String const &t1, QString const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+{
+ return qCompare<QString>(QString(t1), t2, actual, expected, file, line);
+}
+
+template<>
+inline bool qCompare(QStringList const &t1, QStringList const &t2,
+ const char *actual, const char *expected, const char *file, int line)
+{
+ char msg[1024];
+ msg[0] = '\0';
+ bool isOk = true;
+ if (t1.count() != t2.count()) {
+ qt_snprintf(msg, 1024, "Compared QStringLists have different sizes.\n"
+ " Actual (%s) size : '%d'\n"
+ " Expected (%s) size: '%d'", actual, t1.count(), expected, t2.count());
+ isOk = false;
+ }
+ const int min = qMin(t1.count(), t2.count());
+ for (int i = 0; isOk && i < min; ++i) {
+ if (t1.at(i) != t2.at(i)) {
+ qt_snprintf(msg, 1024, "Compared QStringLists differ at index %d.\n"
+ " Actual (%s) : '%s'\n"
+ " Expected (%s) : '%s'", i, actual, t1.at(i).toLatin1().constData(),
+ expected, t2.at(i).toLatin1().constData());
+ isOk = false;
+ }
+ }
+ return compare_helper(isOk, msg, file, line);
+}
+
+template <typename T>
+inline bool qCompare(QFlags<T> const &t1, T const &t2, const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return qCompare(int(t1), int(t2), actual, expected, file, line);
+}
+
+template <typename T>
+inline bool qCompare(QFlags<T> const &t1, int const &t2, const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return qCompare(int(t1), t2, actual, expected, file, line);
+}
+
+}
+QT_END_NAMESPACE
+
+#define QTEST_APPLESS_MAIN(TestObject) \
+int main(int argc, char *argv[]) \
+{ \
+ TestObject tc; \
+ return QTest::qExec(&tc, argc, argv); \
+}
+
+#define QTEST_NOOP_MAIN \
+int main(int argc, char *argv[]) \
+{ \
+ QObject tc; \
+ return QTest::qExec(&tc, argc, argv); \
+}
+
+#include <QtTest/qtestsystem.h>
+
+#ifdef QT_GUI_LIB
+
+#include <QtTest/qtest_gui.h>
+
+#ifdef QT_KEYPAD_NAVIGATION
+# define QTEST_DISABLE_KEYPAD_NAVIGATION QApplication::setNavigationMode(Qt::NavigationModeNone);
+#else
+# define QTEST_DISABLE_KEYPAD_NAVIGATION
+#endif
+
+#define QTEST_MAIN(TestObject) \
+int main(int argc, char *argv[]) \
+{ \
+ QApplication app(argc, argv); \
+ QTEST_DISABLE_KEYPAD_NAVIGATION \
+ TestObject tc; \
+ return QTest::qExec(&tc, argc, argv); \
+}
+
+#else
+
+#define QTEST_MAIN(TestObject) \
+int main(int argc, char *argv[]) \
+{ \
+ QCoreApplication app(argc, argv); \
+ TestObject tc; \
+ return QTest::qExec(&tc, argc, argv); \
+}
+
+#endif // QT_GUI_LIB
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtest_global.h b/src/testlib/qtest_global.h
new file mode 100644
index 0000000000..28c8617712
--- /dev/null
+++ b/src/testlib/qtest_global.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEST_GLOBAL_H
+#define QTEST_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+#ifdef QTEST_EMBED
+# define Q_TESTLIB_EXPORT
+#elif !defined(QT_SHARED) && !(defined(Q_OS_SYMBIAN) && defined(Q_CC_RVCT))
+# define Q_TESTLIB_EXPORT
+#else
+# ifdef QTESTLIB_MAKEDLL
+# define Q_TESTLIB_EXPORT Q_DECL_EXPORT
+# else
+# define Q_TESTLIB_EXPORT Q_DECL_IMPORT
+# endif
+#endif
+
+#if defined (Q_CC_SUN) || defined (Q_CC_XLC) || (defined (Q_CC_GNU) && (__GNUC__ - 0 < 3)) || defined (Q_CC_NOKIAX86)
+# define QTEST_NO_SPECIALIZATIONS
+#endif
+
+
+#if (defined Q_CC_HPACC) && (defined __ia64)
+# ifdef Q_TESTLIB_EXPORT
+# undef Q_TESTLIB_EXPORT
+# endif
+# define Q_TESTLIB_EXPORT
+#endif
+
+#define QTEST_VERSION QT_VERSION
+#define QTEST_VERSION_STR QT_VERSION_STR
+
+namespace QTest
+{
+ enum SkipMode { SkipSingle = 1, SkipAll = 2 };
+ enum TestFailMode { Abort = 1, Continue = 2 };
+
+ int Q_TESTLIB_EXPORT qt_snprintf(char *str, int size, const char *format, ...);
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtest_gui.h b/src/testlib/qtest_gui.h
new file mode 100644
index 0000000000..7d34c3098b
--- /dev/null
+++ b/src/testlib/qtest_gui.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEST_GUI_H
+#define QTEST_GUI_H
+
+// enable GUI features
+#ifndef QT_GUI_LIB
+#define QT_GUI_LIB
+#endif
+#if 0
+#pragma qt_class(QtTestGui)
+#endif
+
+#include <QtTest/qtestassert.h>
+#include <QtTest/qtest.h>
+#include <QtTest/qtestevent.h>
+#include <QtTest/qtestmouse.h>
+#include <QtTest/qtesttouch.h>
+#include <QtTest/qtestkeyboard.h>
+
+#include <QtGui/qicon.h>
+#include <QtGui/qpixmap.h>
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest
+{
+
+template<>
+inline bool qCompare(QIcon const &t1, QIcon const &t2, const char *actual, const char *expected,
+ const char *file, int line)
+{
+ QTEST_ASSERT(sizeof(QIcon) == sizeof(void *));
+ return qCompare<void *>(*reinterpret_cast<void * const *>(&t1),
+ *reinterpret_cast<void * const *>(&t2), actual, expected, file, line);
+}
+
+template<>
+inline bool qCompare(QPixmap const &t1, QPixmap const &t2, const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return qCompare(t1.toImage(), t2.toImage(), actual, expected, file, line);
+}
+
+}
+
+/* compatibility */
+
+inline static bool pixmapsAreEqual(const QPixmap *actual, const QPixmap *expected)
+{
+ if (!actual && !expected)
+ return true;
+ if (!actual || !expected)
+ return false;
+ if (actual->isNull() && expected->isNull())
+ return true;
+ if (actual->isNull() || expected->isNull() || actual->size() != expected->size())
+ return false;
+ return actual->toImage() == expected->toImage();
+}
+
+#ifdef Q_WS_X11
+extern void qt_x11_wait_for_window_manager(QWidget *w);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h
new file mode 100644
index 0000000000..c03b2d2140
--- /dev/null
+++ b/src/testlib/qtestaccessible.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTACCESSIBLE_H
+#define QTESTACCESSIBLE_H
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#define QTEST_ACCESSIBILITY
+
+#define QVERIFY_EVENT(object, child, event) \
+ QVERIFY(QTestAccessibility::verifyEvent(object, child, (int)event))
+
+#include <QtCore/qlist.h>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qapplication.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QObject;
+
+struct QTestAccessibilityEvent
+{
+ QTestAccessibilityEvent(QObject* o = 0, int c = 0, int e = 0)
+ : object(o), child(c), event(e) {}
+
+ bool operator==(const QTestAccessibilityEvent &o) const
+ {
+ return o.object == object && o.child == child && o.event == event;
+ }
+
+ QObject* object;
+ int child;
+ int event;
+};
+
+typedef QList<QTestAccessibilityEvent> EventList;
+
+class QTestAccessibility
+{
+public:
+ static void initialize()
+ {
+ if (!instance()) {
+ instance() = new QTestAccessibility;
+ qAddPostRoutine(cleanup);
+ }
+ }
+ static void cleanup()
+ {
+ delete instance();
+ instance() = 0;
+ }
+ static void clearEvents() { eventList().clear(); }
+ static EventList events() { return eventList(); }
+ static bool verifyEvent(const QTestAccessibilityEvent& ev)
+ {
+ if (eventList().isEmpty())
+ return FALSE;
+ return eventList().takeFirst() == ev;
+ }
+
+ static bool verifyEvent(QObject *o, int c, int e)
+ {
+ return verifyEvent(QTestAccessibilityEvent(o, c, e));
+ }
+
+private:
+ QTestAccessibility()
+ {
+ QAccessible::installUpdateHandler(updateHandler);
+ QAccessible::installRootObjectHandler(rootObjectHandler);
+ }
+
+ ~QTestAccessibility()
+ {
+ QAccessible::installUpdateHandler(0);
+ QAccessible::installRootObjectHandler(0);
+ }
+
+ static void rootObjectHandler(QObject *object)
+ {
+ // qDebug("rootObjectHandler called %p", object);
+ if (object) {
+ QApplication* app = qobject_cast<QApplication*>(object);
+ if ( !app )
+ qWarning("QTEST_ACCESSIBILITY: root Object is not a QApplication!");
+ } else {
+ qWarning("QTEST_ACCESSIBILITY: root Object called with 0 pointer");
+ }
+ }
+
+ static void updateHandler(QObject *o, int c, QAccessible::Event e)
+ {
+ // qDebug("updateHandler called: %p %d %d", o, c, (int)e);
+ eventList().append(QTestAccessibilityEvent(o, c, (int)e));
+ }
+
+ static EventList &eventList()
+ {
+ static EventList list;
+ return list;
+ }
+
+ static QTestAccessibility *&instance()
+ {
+ static QTestAccessibility *ta = 0;
+ return ta;
+ }
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestassert.h b/src/testlib/qtestassert.h
new file mode 100644
index 0000000000..a0847059e0
--- /dev/null
+++ b/src/testlib/qtestassert.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTASSERT_H
+#define QTESTASSERT_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+#define QTEST_ASSERT(cond) do {if(!(cond))qt_assert(#cond,__FILE__,__LINE__);} while (0)
+
+#define QTEST_ASSERT_X(cond, where, what) do {if(!(cond))qt_assert_x(where, what,__FILE__,__LINE__);} while (0)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestbasicstreamer.cpp b/src/testlib/qtestbasicstreamer.cpp
new file mode 100644
index 0000000000..f87137065c
--- /dev/null
+++ b/src/testlib/qtestbasicstreamer.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtestbasicstreamer.h"
+#include "qtestlogger_p.h"
+#include "qtestelement.h"
+#include "qtestelementattribute.h"
+#include "QtTest/private/qtestlog_p.h"
+#include "qtestassert.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef Q_OS_WIN
+#include <unistd.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest
+{
+ static FILE *stream = 0;
+}
+
+QTestBasicStreamer::QTestBasicStreamer()
+ :testLogger(0)
+{
+}
+
+QTestBasicStreamer::~QTestBasicStreamer()
+{}
+
+void QTestBasicStreamer::formatStart(const QTestElement *element, QTestCharBuffer *formatted) const
+{
+ if(!element || !formatted )
+ return;
+ formatted->data()[0] = '\0';
+}
+
+void QTestBasicStreamer::formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const
+{
+ if(!element || !formatted )
+ return;
+ formatted->data()[0] = '\0';
+}
+
+void QTestBasicStreamer::formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const
+{
+ if(!element || !formatted )
+ return;
+ formatted->data()[0] = '\0';
+}
+
+void QTestBasicStreamer::formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const
+{
+ if(!element || !formatted )
+ return;
+ formatted->data()[0] = '\0';
+}
+
+void QTestBasicStreamer::formatAttributes(const QTestElement *, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const
+{
+ if(!attribute || !formatted )
+ return;
+ formatted->data()[0] = '\0';
+}
+
+void QTestBasicStreamer::output(QTestElement *element) const
+{
+ if(!element)
+ return;
+
+ outputElements(element);
+}
+
+void QTestBasicStreamer::outputElements(QTestElement *element, bool) const
+{
+ QTestCharBuffer buf;
+ bool hasChildren;
+ /*
+ Elements are in reverse order of occurrence, so start from the end and work
+ our way backwards.
+ */
+ while (element && element->nextElement()) {
+ element = element->nextElement();
+ }
+ while (element) {
+ hasChildren = element->childElements();
+
+ formatStart(element, &buf);
+ outputString(buf.data());
+
+ formatBeforeAttributes(element, &buf);
+ outputString(buf.data());
+
+ outputElementAttributes(element, element->attributes());
+
+ formatAfterAttributes(element, &buf);
+ outputString(buf.data());
+
+ if(hasChildren)
+ outputElements(element->childElements(), true);
+
+ formatEnd(element, &buf);
+ outputString(buf.data());
+
+ element = element->previousElement();
+ }
+}
+
+void QTestBasicStreamer::outputElementAttributes(const QTestElement* element, QTestElementAttribute *attribute) const
+{
+ QTestCharBuffer buf;
+ while(attribute){
+ formatAttributes(element, attribute, &buf);
+ outputString(buf.data());
+ attribute = attribute->nextElement();
+ }
+}
+
+void QTestBasicStreamer::outputString(const char *msg) const
+{
+ QTEST_ASSERT(QTest::stream);
+
+ ::fputs(msg, QTest::stream);
+ ::fflush(QTest::stream);
+}
+
+void QTestBasicStreamer::startStreaming()
+{
+ QTEST_ASSERT(!QTest::stream);
+
+ const char *out = QTestLog::outputFileName();
+ if (!out) {
+ QTest::stream = stdout;
+ return;
+ }
+ #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE)
+ if (::fopen_s(&QTest::stream, out, "wt")) {
+ #else
+ QTest::stream = ::fopen(out, "wt");
+ if (!QTest::stream) {
+ #endif
+ printf("Unable to open file for logging: %s", out);
+ ::exit(1);
+ }
+}
+
+bool QTestBasicStreamer::isTtyOutput()
+{
+ QTEST_ASSERT(QTest::stream);
+
+#if defined(Q_OS_WIN) || defined(Q_OS_INTEGRITY)
+ return true;
+#else
+ static bool ttyoutput = isatty(fileno(QTest::stream));
+ return ttyoutput;
+#endif
+}
+
+void QTestBasicStreamer::stopStreaming()
+{
+ QTEST_ASSERT(QTest::stream);
+ if (QTest::stream != stdout)
+ fclose(QTest::stream);
+
+ QTest::stream = 0;
+}
+
+void QTestBasicStreamer::setLogger(const QTestLogger *tstLogger)
+{
+ testLogger = tstLogger;
+}
+
+const QTestLogger *QTestBasicStreamer::logger() const
+{
+ return testLogger;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/testlib/qtestbasicstreamer.h b/src/testlib/qtestbasicstreamer.h
new file mode 100644
index 0000000000..410b97098f
--- /dev/null
+++ b/src/testlib/qtestbasicstreamer.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTBASICSTREAMER_H
+#define QTESTBASICSTREAMER_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QTestElement;
+class QTestElementAttribute;
+class QTestLogger;
+struct QTestCharBuffer;
+
+class QTestBasicStreamer
+{
+ public:
+ QTestBasicStreamer();
+ virtual ~QTestBasicStreamer();
+
+ virtual void output(QTestElement *element) const;
+
+ void outputString(const char *msg) const;
+ bool isTtyOutput();
+ void startStreaming();
+ void stopStreaming();
+
+ void setLogger(const QTestLogger *tstLogger);
+ const QTestLogger *logger() const;
+
+ protected:
+ virtual void formatStart(const QTestElement *element, QTestCharBuffer *formatted) const;
+ virtual void formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const;
+ virtual void formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const;
+ virtual void formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const;
+ virtual void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const;
+ virtual void outputElements(QTestElement *element, bool isChildElement = false) const;
+ virtual void outputElementAttributes(const QTestElement *element, QTestElementAttribute *attribute) const;
+
+ private:
+ const QTestLogger *testLogger;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
new file mode 100644
index 0000000000..9a0d08726f
--- /dev/null
+++ b/src/testlib/qtestcase.cpp
@@ -0,0 +1,2332 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/qtestcase.h"
+#include "QtTest/qtestassert.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qprocess.h>
+#include <QtCore/qdebug.h>
+
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/private/qtesttable_p.h"
+#include "QtTest/qtestdata.h"
+#include "QtTest/private/qtestresult_p.h"
+#include "QtTest/private/qsignaldumper_p.h"
+#include "QtTest/private/qbenchmark_p.h"
+#include "3rdparty/cycle_p.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef Q_OS_WIN
+#include <windows.h> // for Sleep
+#endif
+#ifdef Q_OS_UNIX
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#endif
+
+#ifdef Q_WS_MAC
+#include <Carbon/Carbon.h> // for SetFrontProcess
+#ifdef QT_MAC_USE_COCOA
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#else
+#include <Security/AuthSession.h>
+#endif
+#undef verify
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \namespace QTest
+ \inmodule QtTest
+
+ \brief The QTest namespace contains all the functions and
+ declarations that are related to the QTestLib tool.
+
+ Please refer to the \l{QTestLib Manual} documentation for information on
+ how to write unit tests.
+*/
+
+/*! \macro QVERIFY(condition)
+
+ \relates QTest
+
+ The QVERIFY() macro checks whether the \a condition is true or not. If it is
+ true, execution continues. If not, a failure is recorded in the test log
+ and the test won't be executed further.
+
+ \bold {Note:} This macro can only be used in a test function that is invoked
+ by the test framework.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 0
+
+ \sa QCOMPARE()
+*/
+
+/*! \macro QVERIFY2(condition, message)
+
+ \relates QTest
+
+ The QVERIFY2() macro behaves exactly like QVERIFY(), except that it outputs
+ a verbose \a message when \a condition is false. The \a message is a plain
+ C string.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 1
+
+ \sa QVERIFY(), QCOMPARE()
+*/
+
+/*! \macro QCOMPARE(actual, expected)
+
+ \relates QTest
+
+ The QCOMPARE macro compares an \a actual value to an \a expected value using
+ the equals operator. If \a actual and \a expected are identical, execution
+ continues. If not, a failure is recorded in the test log and the test
+ won't be executed further.
+
+ In the case of comparing floats and doubles, qFuzzyCompare() is used for
+ comparing. This means that comparing to 0 will likely fail. One solution
+ to this is to compare to 1, and add 1 to the produced output.
+
+ QCOMPARE tries to output the contents of the values if the comparison fails,
+ so it is visible from the test log why the comparison failed.
+
+ QCOMPARE is very strict on the data types. Both \a actual and \a expected
+ have to be of the same type, otherwise the test won't compile. This prohibits
+ unspecified behavior from being introduced; that is behavior that usually
+ occurs when the compiler implicitly casts the argument.
+
+ If you use QCOMPARE() to compare two QStringList objects, it will start
+ comparing the objects from the end of the lists.
+
+ For your own classes, you can use \l QTest::toString() to format values for
+ outputting into the test log.
+
+ \note This macro can only be used in a test function that is invoked
+ by the test framework.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 2
+
+ \sa QVERIFY(), QTest::toString()
+*/
+
+/*! \macro QFETCH(type, name)
+
+ \relates QTest
+
+ The fetch macro creates a local variable named \a name with the type \a type
+ on the stack. \a name has to match the element name from the test's data.
+ If no such element exists, the test will assert.
+
+ Assuming a test has the following data:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 3
+
+ The test data has two elements, a QString called \c aString and an integer
+ called \c expected. To fetch these values in the actual test:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 4
+
+ \c aString and \c expected are variables on the stack that are initialized with
+ the current test data.
+
+ \bold {Note:} This macro can only be used in a test function that is invoked
+ by the test framework. The test function must have a _data function.
+*/
+
+/*! \macro QWARN(message)
+
+ \relates QTest
+ \threadsafe
+
+ Appends \a message as a warning to the test log. This macro can be used anywhere
+ in your tests.
+*/
+
+/*! \macro QFAIL(message)
+
+ \relates QTest
+
+ This macro can be used to force a test failure. The test stops
+ executing and the failure \a message is appended to the test log.
+
+ \bold {Note:} This macro can only be used in a test function that is invoked
+ by the test framework.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 5
+*/
+
+/*! \macro QTEST(actual, testElement)
+
+ \relates QTest
+
+ QTEST() is a convenience macro for \l QCOMPARE() that compares
+ the value \a actual with the element \a testElement from the test's data.
+ If there is no such element, the test asserts.
+
+ Apart from that, QTEST() behaves exactly as \l QCOMPARE().
+
+ Instead of writing:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 6
+
+ you can write:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 7
+
+ \sa QCOMPARE()
+*/
+
+/*! \macro QSKIP(description, mode)
+
+ \relates QTest
+
+ The QSKIP() macro stops execution of the test without adding a failure to the
+ test log. You can use it to skip tests that wouldn't make sense in the current
+ configuration. The text \a description is appended to the test log and should
+ contain an explanation why the test couldn't be executed. \a mode is a QTest::SkipMode
+ and describes whether to proceed with the rest of the test data or not.
+
+ \bold {Note:} This macro can only be used in a test function that is invoked
+ by the test framework.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 8
+
+ \sa QTest::SkipMode
+*/
+
+/*! \macro QEXPECT_FAIL(dataIndex, comment, mode)
+
+ \relates QTest
+
+ The QEXPECT_FAIL() macro marks the next \l QCOMPARE() or \l QVERIFY() as an
+ expected failure. Instead of adding a failure to the test log, an expected
+ failure will be reported.
+
+ If a \l QVERIFY() or \l QCOMPARE() is marked as an expected failure,
+ but passes instead, an unexpected pass (XPASS) is written to the test log.
+
+ The parameter \a dataIndex describes for which entry in the test data the
+ failure is expected. Pass an empty string (\c{""}) if the failure
+ is expected for all entries or if no test data exists.
+
+ \a comment will be appended to the test log for the expected failure.
+
+ \a mode is a \l QTest::TestFailMode and sets whether the test should
+ continue to execute or not.
+
+ \bold {Note:} This macro can only be used in a test function that is invoked
+ by the test framework.
+
+ Example 1:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 9
+
+ In the example above, an expected fail will be written into the test output
+ if the variable \c i is not 42. If the variable \c i is 42, an unexpected pass
+ is written instead. The QEXPECT_FAIL() has no influence on the second QCOMPARE()
+ statement in the example.
+
+ Example 2:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 10
+
+ The above testfunction will not continue executing for the test data
+ entry \c{data27}.
+
+ \sa QTest::TestFailMode, QVERIFY(), QCOMPARE()
+*/
+
+/*! \macro QTEST_MAIN(TestClass)
+
+ \relates QTest
+
+ Implements a main() function that instantiates an application object and
+ the \a TestClass, and executes all tests in the order they were defined.
+ Use this macro to build stand-alone executables.
+
+ If \c QT_GUI_LIB is defined, the application object will be a QApplication,
+ otherwise it will be a QCoreApplication. If qmake is used and the configuration
+ includes \c{QT += gui}, then \c QT_GUI_LIB will be defined automatically.
+
+ \bold {Note:} On platforms that have keypad navigation enabled by default (eg: Symbian),
+ this macro will forcfully disable it to simplify the usage of key events when writing
+ autotests. If you wish to write a test case that uses keypad navigation, you should
+ enable it either in the \c {initTestCase()} or \c {init()} functions of your test case.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 11
+
+ \sa QTEST_APPLESS_MAIN(), QTest::qExec(), QApplication::setNavigationMode()
+*/
+
+/*! \macro QTEST_APPLESS_MAIN(TestClass)
+
+ \relates QTest
+
+ Implements a main() function that executes all tests in \a TestClass.
+
+ Behaves like \l QTEST_MAIN(), but doesn't instantiate a QApplication
+ object. Use this macro for really simple stand-alone non-GUI tests.
+
+ \sa QTEST_MAIN()
+*/
+
+/*! \macro QTEST_NOOP_MAIN()
+
+ \relates QTest
+
+ Implements a main() function with a test class that does absolutely nothing.
+ Use this macro to create a test that produces valid test output but just
+ doesn't execute any test, for example in conditional compilations:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 12
+
+ \sa QTEST_MAIN()
+*/
+
+/*!
+ \macro QBENCHMARK
+
+ \relates QTest
+
+ This macro is used to measure the performance of code within a test.
+ The code to be benchmarked is contained within a code block following
+ this macro.
+
+ For example:
+
+ \snippet examples/qtestlib/tutorial5/benchmarking.cpp 0
+
+ \sa {QTestLib Manual#Creating a Benchmark}{Creating a Benchmark},
+ {Chapter 5: Writing a Benchmark}{Writing a Benchmark}
+*/
+
+/*!
+ \macro QBENCHMARK_ONCE
+ \since 4.6
+
+ \relates QTest
+
+ \brief The QBENCHMARK_ONCE macro is for measuring performance of a
+ code block by running it once.
+
+ This macro is used to measure the performance of code within a test.
+ The code to be benchmarked is contained within a code block following
+ this macro.
+
+ Unlike QBENCHMARK, the contents of the contained code block is only run
+ once. The elapsed time will be reported as "0" if it's to short to
+ be measured by the selected backend. (Use)
+
+ \sa {QTestLib Manual#Creating a Benchmark}{Creating a Benchmark},
+ {Chapter 5: Writing a Benchmark}{Writing a Benchmark}
+*/
+
+
+
+/*! \enum QTest::SkipMode
+
+ This enum describes the modes for skipping tests during execution
+ of the test data.
+
+ \value SkipSingle Skips the current entry in the test table; continues
+ execution of all the other entries in the table.
+
+ \value SkipAll Skips all the entries in the test table; the test won't
+ be executed further.
+
+ \sa QSKIP()
+*/
+
+/*! \enum QTest::TestFailMode
+
+ This enum describes the modes for handling an expected failure of the
+ \l QVERIFY() or \l QCOMPARE() macros.
+
+ \value Abort Aborts the execution of the test. Use this mode when it
+ doesn't make sense to execute the test any further after the
+ expected failure.
+
+ \value Continue Continues execution of the test after the expected failure.
+
+ \sa QEXPECT_FAIL()
+*/
+
+/*! \enum QTest::KeyAction
+
+ This enum describes possible actions for key handling.
+
+ \value Press The key is pressed.
+ \value Release The key is released.
+ \value Click The key is clicked (pressed and released).
+*/
+
+/*! \enum QTest::MouseAction
+
+ This enum describes possible actions for mouse handling.
+
+ \value MousePress A mouse button is pressed.
+ \value MouseRelease A mouse button is released.
+ \value MouseClick A mouse button is clicked (pressed and released).
+ \value MouseDClick A mouse button is double clicked (pressed and released twice).
+ \value MouseMove The mouse pointer has moved.
+*/
+
+/*! \fn void QTest::keyClick(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ \overload
+
+ Simulates clicking of \a key with an optional \a modifier on a \a widget.
+ If \a delay is larger than 0, the test will wait for \a delay milliseconds.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 13
+
+ The example above simulates clicking \c a on \c myWidget without
+ any keyboard modifiers and without delay of the test.
+
+ \sa QTest::keyClicks()
+*/
+
+/*! \fn void QTest::keyClick(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ Simulates clicking of \a key with an optional \a modifier on a \a widget.
+ If \a delay is larger than 0, the test will wait for \a delay milliseconds.
+
+ Examples:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 14
+
+ The first example above simulates clicking the \c escape key on \c
+ myWidget without any keyboard modifiers and without delay. The
+ second example simulates clicking \c shift-escape on \c myWidget
+ with a following 200 ms delay of the test.
+
+ \sa QTest::keyClicks()
+*/
+
+/*! \fn void QTest::keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ Sends a Qt key event to \a widget with the given \a key and an associated \a action.
+ Optionally, a keyboard \a modifier can be specified, as well as a \a delay
+ (in milliseconds) of the test before sending the event.
+*/
+
+/*! \fn void QTest::keyEvent(KeyAction action, QWidget *widget, char ascii, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ \overload
+
+ Sends a Qt key event to \a widget with the given key \a ascii and an associated \a action.
+ Optionally, a keyboard \a modifier can be specified, as well as a \a delay
+ (in milliseconds) of the test before sending the event.
+
+*/
+
+/*! \fn void QTest::keyPress(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ Simulates pressing a \a key with an optional \a modifier on a \a widget. If \a delay
+ is larger than 0, the test will wait for \a delay milliseconds.
+
+ \bold {Note:} At some point you should release the key using \l keyRelease().
+
+ \sa QTest::keyRelease(), QTest::keyClick()
+*/
+
+/*! \fn void QTest::keyPress(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ \overload
+
+ Simulates pressing a \a key with an optional \a modifier on a \a widget.
+ If \a delay is larger than 0, the test will wait for \a delay milliseconds.
+
+ \bold {Note:} At some point you should release the key using \l keyRelease().
+
+ \sa QTest::keyRelease(), QTest::keyClick()
+*/
+
+/*! \fn void QTest::keyRelease(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ Simulates releasing a \a key with an optional \a modifier on a \a widget.
+ If \a delay is larger than 0, the test will wait for \a delay milliseconds.
+
+ \sa QTest::keyPress(), QTest::keyClick()
+*/
+
+/*! \fn void QTest::keyRelease(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ \overload
+
+ Simulates releasing a \a key with an optional \a modifier on a \a widget.
+ If \a delay is larger than 0, the test will wait for \a delay milliseconds.
+
+ \sa QTest::keyClick()
+*/
+
+
+/*! \fn void QTest::keyClicks(QWidget *widget, const QString &sequence, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+
+ Simulates clicking a \a sequence of keys on a \a
+ widget. Optionally, a keyboard \a modifier can be specified as
+ well as a \a delay (in milliseconds) of the test before each key
+ click.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 15
+
+ The example above simulates clicking the sequence of keys
+ representing "hello world" on \c myWidget without any keyboard
+ modifiers and without delay of the test.
+
+ \sa QTest::keyClick()
+*/
+
+/*! \fn void QTest::mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Simulates pressing a mouse \a button with an optional \a modifier
+ on a \a widget. The position is defined by \a pos; the default
+ position is the center of the widget. If \a delay is specified,
+ the test will wait for the specified amount of milliseconds before
+ the press.
+
+ \sa QTest::mouseRelease(), QTest::mouseClick()
+*/
+
+/*! \fn void QTest::mouseRelease(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Simulates releasing a mouse \a button with an optional \a modifier
+ on a \a widget. The position of the release is defined by \a pos;
+ the default position is the center of the widget. If \a delay is
+ specified, the test will wait for the specified amount of
+ milliseconds before releasing the button.
+
+ \sa QTest::mousePress(), QTest::mouseClick()
+*/
+
+/*! \fn void QTest::mouseClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Simulates clicking a mouse \a button with an optional \a modifier
+ on a \a widget. The position of the click is defined by \a pos;
+ the default position is the center of the widget. If \a delay is
+ specified, the test will wait for the specified amount of
+ milliseconds before pressing and before releasing the button.
+
+ \sa QTest::mousePress(), QTest::mouseRelease()
+*/
+
+/*! \fn void QTest::mouseDClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Simulates double clicking a mouse \a button with an optional \a
+ modifier on a \a widget. The position of the click is defined by
+ \a pos; the default position is the center of the widget. If \a
+ delay is specified, the test will wait for the specified amount of
+ milliseconds before each press and release.
+
+ \sa QTest::mouseClick()
+*/
+
+/*! \fn void QTest::mouseMove(QWidget *widget, QPoint pos = QPoint(), int delay=-1)
+
+ Moves the mouse pointer to a \a widget. If \a pos is not
+ specified, the mouse pointer moves to the center of the widget. If
+ a \a delay (in milliseconds) is given, the test will wait before
+ moving the mouse pointer.
+*/
+
+/*!
+ \fn char *QTest::toString(const T &value)
+
+ Returns a textual representation of \a value. This function is used by
+ \l QCOMPARE() to output verbose information in case of a test failure.
+
+ You can add specializations of this function to your test to enable
+ verbose output.
+
+ \bold {Note:} The caller of toString() must delete the returned data
+ using \c{delete[]}. Your implementation should return a string
+ created with \c{new[]} or qstrdup().
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 16
+
+ The example above defines a toString() specialization for a class
+ called \c MyPoint. Whenever a comparison of two instances of \c
+ MyPoint fails, \l QCOMPARE() will call this function to output the
+ contents of \c MyPoint to the test log.
+
+ \sa QCOMPARE()
+*/
+
+/*!
+ \fn char *QTest::toString(const QLatin1String &string)
+ \overload
+
+ Returns a textual representation of the given \a string.
+*/
+
+/*!
+ \fn char *QTest::toString(const QString &string)
+ \overload
+
+ Returns a textual representation of the given \a string.
+*/
+
+/*!
+ \fn char *QTest::toString(const QByteArray &ba)
+ \overload
+
+ Returns a textual representation of the byte array \a ba.
+
+ \sa QTest::toHexRepresentation()
+*/
+
+/*!
+ \fn char *QTest::toString(const QTime &time)
+ \overload
+
+ Returns a textual representation of the given \a time.
+*/
+
+/*!
+ \fn char *QTest::toString(const QDate &date)
+ \overload
+
+ Returns a textual representation of the given \a date.
+*/
+
+/*!
+ \fn char *QTest::toString(const QDateTime &dateTime)
+ \overload
+
+ Returns a textual representation of the date and time specified by
+ \a dateTime.
+*/
+
+/*!
+ \fn char *QTest::toString(const QChar &character)
+ \overload
+
+ Returns a textual representation of the given \a character.
+*/
+
+/*!
+ \fn char *QTest::toString(const QPoint &point)
+ \overload
+
+ Returns a textual representation of the given \a point.
+*/
+
+/*!
+ \fn char *QTest::toString(const QSize &size)
+ \overload
+
+ Returns a textual representation of the given \a size.
+*/
+
+/*!
+ \fn char *QTest::toString(const QRect &rectangle)
+ \overload
+
+ Returns a textual representation of the given \a rectangle.
+*/
+
+/*!
+ \fn char *QTest::toString(const QUrl &url)
+ \since 4.4
+ \overload
+
+ Returns a textual representation of the given \a url.
+*/
+
+/*!
+ \fn char *QTest::toString(const QPointF &point)
+ \overload
+
+ Returns a textual representation of the given \a point.
+*/
+
+/*!
+ \fn char *QTest::toString(const QSizeF &size)
+ \overload
+
+ Returns a textual representation of the given \a size.
+*/
+
+/*!
+ \fn char *QTest::toString(const QRectF &rectangle)
+ \overload
+
+ Returns a textual representation of the given \a rectangle.
+*/
+
+/*!
+ \fn char *QTest::toString(const QVariant &variant)
+ \overload
+
+ Returns a textual representation of the given \a variant.
+*/
+
+/*! \fn void QTest::qWait(int ms)
+
+ Waits for \a ms milliseconds. While waiting, events will be processed and
+ your test will stay responsive to user interface events or network communication.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 17
+
+ The code above will wait until the network server is responding for a
+ maximum of about 12.5 seconds.
+
+ \sa QTest::qSleep()
+*/
+
+/*! \fn bool QTest::qWaitForWindowShown(QWidget *window)
+ \since 4.6
+
+ Waits until the \a window is shown in the screen. This is mainly useful for
+ asynchronous systems like X11, where a window will be mapped to screen some
+ time after being asked to show itself on the screen. Returns true.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 24
+*/
+
+/*!
+ \class QTest::QTouchEventSequence
+ \inmodule QtTest
+ \since 4.6
+
+ \brief The QTouchEventSequence class is used to simulate a sequence of touch events.
+
+ To simulate a sequence of touch events on a specific device for a widget, call
+ QTest::touchEvent to create a QTouchEventSequence instance. Add touch events to
+ the sequence by calling press(), move(), release() and stationary(), and let the
+ instance run out of scope to commit the sequence to the event system.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 25
+*/
+
+/*!
+ \fn QTest::QTouchEventSequence::~QTouchEventSequence()
+
+ Commits this sequence of touch events and frees allocated resources.
+*/
+
+/*!
+ \fn QTouchEventSequence &QTest::QTouchEventSequence::press(int touchId, const QPoint &pt, QWidget *widget)
+
+ Adds a press event for touchpoint \a touchId at position \a pt to this sequence and returns
+ a reference to this QTouchEventSequence.
+
+ The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then
+ \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence.
+
+ Simulates that the user pressed the touch screen or pad with the finger identified by \a touchId.
+*/
+
+/*!
+ \fn QTouchEventSequence &QTest::QTouchEventSequence::move(int touchId, const QPoint &pt, QWidget *widget)
+
+ Adds a move event for touchpoint \a touchId at position \a pt to this sequence and returns
+ a reference to this QTouchEventSequence.
+
+ The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then
+ \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence.
+
+ Simulates that the user moved the finger identified by \a touchId.
+*/
+
+/*!
+ \fn QTouchEventSequence &QTest::QTouchEventSequence::release(int touchId, const QPoint &pt, QWidget *widget)
+
+ Adds a release event for touchpoint \a touchId at position \a pt to this sequence and returns
+ a reference to this QTouchEventSequence.
+
+ The position \a pt is interpreted as relative to \a widget. If \a widget is the null pointer, then
+ \a pt is interpreted as relative to the widget provided when instantiating this QTouchEventSequence.
+
+ Simulates that the user lifted the finger identified by \a touchId.
+*/
+
+/*!
+ \fn QTouchEventSequence &QTest::QTouchEventSequence::stationary(int touchId)
+
+ Adds a stationary event for touchpoint \a touchId to this sequence and returns
+ a reference to this QTouchEventSequence.
+
+ Simulates that the user did not move the finger identified by \a touchId.
+*/
+
+/*!
+ \fn QTouchEventSequence QTest::touchEvent(QWidget *widget, QTouchEvent::DeviceType deviceType)
+
+ Creates and returns a QTouchEventSequence for the device \a deviceType to
+ simulate events for \a widget.
+
+ When adding touch events to the sequence, \a widget will also be used to translate
+ the position provided to screen coordinates, unless another widget is provided in the
+ respective calls to press(), move() etc.
+
+ The touch events are committed to the event system when the destructor of the
+ QTouchEventSequence is called (ie when the object returned runs out of scope).
+*/
+
+namespace QTest
+{
+ static QObject *currentTestObject = 0;
+
+ class TestFunction {
+ public:
+ TestFunction() : function_(-1), data_(0) {}
+ void set(int function, char *data) { function_ = function; data_ = data; }
+ char *data() const { return data_; }
+ int function() const { return function_; }
+ ~TestFunction() { delete[] data_; }
+ private:
+ int function_;
+ char *data_;
+ };
+ /**
+ * Contains the list of test functions that was supplied
+ * on the command line, if any. Hence, if not empty,
+ * those functions should be run instead of
+ * all appearing in the test case.
+ */
+ static TestFunction * testFuncs = 0;
+ static int testFuncCount = 0;
+
+ /** Don't leak testFuncs on exit even on error */
+ static struct TestFuncCleanup
+ {
+ void cleanup()
+ {
+ delete[] testFuncs;
+ testFuncCount = 0;
+ testFuncs = 0;
+ }
+
+ ~TestFuncCleanup() { cleanup(); }
+ } testFuncCleaner;
+
+ static int keyDelay = -1;
+ static int mouseDelay = -1;
+ static int eventDelay = -1;
+ static bool randomOrder = false;
+ static int keyVerbose = -1;
+ static unsigned int seed = 0;
+ static bool seedSet = false;
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ static bool noCrashHandler = false;
+#endif
+
+void filter_unprintable(char *str)
+{
+ char *idx = str;
+ while (*idx) {
+ if (((*idx < 0x20 && *idx != '\n' && *idx != '\t') || *idx > 0x7e))
+ *idx = '?';
+ ++idx;
+ }
+}
+
+/*! \internal
+ */
+int qt_snprintf(char *str, int size, const char *format, ...)
+{
+ va_list ap;
+ int res = 0;
+
+ va_start(ap, format);
+ qvsnprintf(str, size, format, ap);
+ va_end(ap);
+ str[size - 1] = '\0';
+
+ filter_unprintable(str);
+
+ return res;
+}
+
+/*! \internal
+ Invoke a method of the object without generating warning if the method does not exist
+ */
+static void invokeMethod(QObject *obj, const char *methodName)
+{
+ const QMetaObject *metaObject = obj->metaObject();
+ int funcIndex = metaObject->indexOfMethod(methodName);
+ if (funcIndex >= 0) {
+ QMetaMethod method = metaObject->method(funcIndex);
+ method.invoke(obj, Qt::DirectConnection);
+ }
+}
+
+bool Q_TESTLIB_EXPORT defaultKeyVerbose()
+{
+ if (keyVerbose == -1) {
+ keyVerbose = qgetenv("QTEST_KEYEVENT_VERBOSE").constData() ? 1 : 0;
+ }
+ return keyVerbose == 1;
+}
+
+int defaultEventDelay()
+{
+ if (eventDelay == -1) {
+ if (qgetenv("QTEST_EVENT_DELAY").constData())
+ eventDelay = atoi(qgetenv("QTEST_EVENT_DELAY"));
+ else
+ eventDelay = 0;
+ }
+ return eventDelay;
+}
+
+int Q_TESTLIB_EXPORT defaultMouseDelay()
+{
+ if (mouseDelay == -1) {
+ if (qgetenv("QTEST_MOUSEEVENT_DELAY").constData())
+ mouseDelay = atoi((qgetenv("QTEST_MOUSEEVENT_DELAY")));
+ else
+ mouseDelay = defaultEventDelay();
+ }
+ return mouseDelay;
+}
+
+int Q_TESTLIB_EXPORT defaultKeyDelay()
+{
+ if (keyDelay == -1) {
+ if (qgetenv("QTEST_KEYEVENT_DELAY").constData())
+ keyDelay = atoi(qgetenv("QTEST_KEYEVENT_DELAY").constData());
+ else
+ keyDelay = defaultEventDelay();
+ }
+ return keyDelay;
+}
+
+void seedRandom()
+{
+ static bool randomSeeded = false;
+ if (!randomSeeded) {
+ if (!QTest::seedSet) {
+ QElapsedTimer timer;
+ timer.start();
+ QTest::seed = timer.msecsSinceReference();
+ }
+ qsrand(QTest::seed);
+ randomSeeded = true;
+ }
+}
+
+int qTestRandomSeed()
+{
+ Q_ASSERT(QTest::seedSet);
+ return QTest::seed;
+}
+
+template<typename T>
+void swap(T * array, int pos, int otherPos)
+{
+ T tmp = array[pos];
+ array[pos] = array[otherPos];
+ array[otherPos] = tmp;
+}
+
+template<typename T>
+static void randomizeList(T * array, int size)
+{
+ for (int i = 0; i != size; i++) {
+ int pos = qrand() % size;
+ swap(array, pos, i);
+ }
+}
+
+static bool isValidSlot(const QMetaMethod &sl)
+{
+ if (sl.access() != QMetaMethod::Private || !sl.parameterTypes().isEmpty()
+ || qstrlen(sl.typeName()) || sl.methodType() != QMetaMethod::Slot)
+ return false;
+ const char *sig = sl.signature();
+ int len = qstrlen(sig);
+ if (len < 2)
+ return false;
+ if (sig[len - 2] != '(' || sig[len - 1] != ')')
+ return false;
+ if (len > 7 && strcmp(sig + (len - 7), "_data()") == 0)
+ return false;
+ if (strcmp(sig, "initTestCase()") == 0 || strcmp(sig, "cleanupTestCase()") == 0
+ || strcmp(sig, "cleanup()") == 0 || strcmp(sig, "init()") == 0)
+ return false;
+ return true;
+}
+
+Q_TESTLIB_EXPORT bool printAvailableFunctions = false;
+Q_TESTLIB_EXPORT QStringList testFunctions;
+Q_TESTLIB_EXPORT QStringList testTags;
+
+static void qPrintTestSlots()
+{
+ for (int i = 0; i < QTest::currentTestObject->metaObject()->methodCount(); ++i) {
+ QMetaMethod sl = QTest::currentTestObject->metaObject()->method(i);
+ if (isValidSlot(sl))
+ printf("%s\n", sl.signature());
+ }
+}
+
+static int qToInt(char *str)
+{
+ char *pEnd;
+ int l = (int)strtol(str, &pEnd, 10);
+ if (*pEnd != 0) {
+ printf("Invalid numeric parameter: '%s'\n", str);
+ exit(1);
+ }
+ return l;
+}
+
+Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
+{
+ const char *testOptions =
+ " options:\n"
+ " -functions : Returns a list of current testfunctions\n"
+ " -xunitxml : Outputs results as XML XUnit document\n"
+ " -xml : Outputs results as XML document\n"
+ " -lightxml : Outputs results as stream of XML tags\n"
+ " -flush : Flushes the results\n"
+ " -o filename: Writes all output into a file\n"
+ " -silent : Only outputs warnings and failures\n"
+ " -v1 : Print enter messages for each testfunction\n"
+ " -v2 : Also print out each QVERIFY/QCOMPARE/QTEST\n"
+ " -vs : Print every signal emitted\n"
+ " -random : Run testcases within each test in random order\n"
+ " -seed n : Positive integer to be used as seed for -random. If not specified,\n"
+ " the current time will be used as seed.\n"
+ " -eventdelay ms : Set default delay for mouse and keyboard simulation to ms milliseconds\n"
+ " -keydelay ms : Set default delay for keyboard simulation to ms milliseconds\n"
+ " -mousedelay ms : Set default delay for mouse simulation to ms milliseconds\n"
+ " -keyevent-verbose : Turn on verbose messages for keyboard simulation\n"
+ " -maxwarnings n : Sets the maximum amount of messages to output.\n"
+ " 0 means unlimited, default: 2000\n"
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ " -nocrashhandler : Disables the crash handler\n"
+#endif
+ "\n"
+ " Benchmark related options:\n"
+#ifdef QTESTLIB_USE_VALGRIND
+ " -callgrind : Use callgrind to time benchmarks\n"
+#endif
+#ifdef HAVE_TICK_COUNTER
+ " -tickcounter : Use CPU tick counters to time benchmarks\n"
+#endif
+ " -eventcounter : Counts events received during benchmarks\n"
+ " -minimumvalue n : Sets the minimum acceptable measurement value\n"
+ " -iterations n : Sets the number of accumulation iterations.\n"
+ " -median n : Sets the number of median iterations.\n"
+ " -vb : Print out verbose benchmarking information.\n"
+ "\n"
+ " -help : This help\n";
+
+ for (int i = 1; i < argc; ++i) {
+ if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "--help") == 0
+ || strcmp(argv[i], "/?") == 0) {
+ printf(" Usage: %s [options] [testfunction[:testdata]]...\n"
+ " By default, all testfunctions will be run.\n\n"
+ "%s", argv[0], testOptions);
+ exit(0);
+ } else if (strcmp(argv[i], "-functions") == 0) {
+ if (qml) {
+ QTest::printAvailableFunctions = true;
+ } else {
+ qPrintTestSlots();
+ exit(0);
+ }
+ } else if(strcmp(argv[i], "-xunitxml") == 0){
+ QTestLog::setLogMode(QTestLog::XunitXML);
+ } else if (strcmp(argv[i], "-xml") == 0) {
+ QTestLog::setLogMode(QTestLog::XML);
+ } else if (strcmp(argv[i], "-lightxml") == 0) {
+ QTestLog::setLogMode(QTestLog::LightXML);
+ }else if(strcmp(argv[i], "-flush") == 0){
+ QTestLog::setFlushMode(QTestLog::FLushOn);
+ } else if (strcmp(argv[i], "-silent") == 0) {
+ QTestLog::setVerboseLevel(-1);
+ } else if (strcmp(argv[i], "-v1") == 0) {
+ QTestLog::setVerboseLevel(1);
+ } else if (strcmp(argv[i], "-v2") == 0) {
+ QTestLog::setVerboseLevel(2);
+ } else if (strcmp(argv[i], "-vs") == 0) {
+ QSignalDumper::startDump();
+ } else if (strcmp(argv[i], "-o") == 0) {
+ if (i + 1 >= argc) {
+ printf("-o needs an extra parameter specifying the filename\n");
+ exit(1);
+ } else {
+ QTestLog::redirectOutput(argv[++i]);
+ }
+ } else if (strcmp(argv[i], "-eventdelay") == 0) {
+ if (i + 1 >= argc) {
+ printf("-eventdelay needs an extra parameter to indicate the delay(ms)\n");
+ exit(1);
+ } else {
+ QTest::eventDelay = qToInt(argv[++i]);
+ }
+ } else if (strcmp(argv[i], "-keydelay") == 0) {
+ if (i + 1 >= argc) {
+ printf("-keydelay needs an extra parameter to indicate the delay(ms)\n");
+ exit(1);
+ } else {
+ QTest::keyDelay = qToInt(argv[++i]);
+ }
+ } else if (strcmp(argv[i], "-mousedelay") == 0) {
+ if (i + 1 >= argc) {
+ printf("-mousedelay needs an extra parameter to indicate the delay(ms)\n");
+ exit(1);
+ } else {
+ QTest::mouseDelay = qToInt(argv[++i]);
+ }
+ } else if (strcmp(argv[i], "-maxwarnings") == 0) {
+ if (i + 1 >= argc) {
+ printf("-maxwarnings needs an extra parameter with the amount of warnings\n");
+ exit(1);
+ } else {
+ QTestLog::setMaxWarnings(qToInt(argv[++i]));
+ }
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ } else if (strcmp(argv[i], "-nocrashhandler") == 0) {
+ QTest::noCrashHandler = true;
+#endif
+ } else if (strcmp(argv[i], "-keyevent-verbose") == 0) {
+ QTest::keyVerbose = 1;
+#ifdef QTESTLIB_USE_VALGRIND
+ } else if (strcmp(argv[i], "-callgrind") == 0) {
+ if (QBenchmarkValgrindUtils::haveValgrind())
+ if (QFileInfo(QDir::currentPath()).isWritable()) {
+ QBenchmarkGlobalData::current->setMode(QBenchmarkGlobalData::CallgrindParentProcess);
+ } else {
+ printf("WARNING: Current directory not writable. Using the walltime measurer.\n");
+ }
+ else {
+ printf("WARNING: Valgrind not found or too old. Make sure it is installed and in your path. "
+ "Using the walltime measurer.\n");
+ }
+ } else if (strcmp(argv[i], "-callgrindchild") == 0) { // "private" option
+ QBenchmarkGlobalData::current->setMode(QBenchmarkGlobalData::CallgrindChildProcess);
+ QBenchmarkGlobalData::current->callgrindOutFileBase =
+ QBenchmarkValgrindUtils::outFileBase();
+#endif
+#ifdef HAVE_TICK_COUNTER
+ } else if (strcmp(argv[i], "-tickcounter") == 0) {
+ QBenchmarkGlobalData::current->setMode(QBenchmarkGlobalData::TickCounter);
+#endif
+ } else if (strcmp(argv[i], "-eventcounter") == 0) {
+ QBenchmarkGlobalData::current->setMode(QBenchmarkGlobalData::EventCounter);
+ } else if (strcmp(argv[i], "-random") == 0) {
+ QTest::randomOrder = true;
+ } else if (strcmp(argv[i], "-seed") == 0) {
+ bool argumentOk = false;
+ if (i + 1 < argc) {
+ char * endpt = 0;
+ long longSeed = strtol(argv[++i], &endpt, 10);
+ argumentOk = (*endpt == '\0' && longSeed >= 0);
+ QTest::seed = longSeed;
+ }
+ if (!argumentOk) {
+ printf("-seed needs an extra positive integer parameter to specify the seed\n");
+ exit(1);
+ } else {
+ QTest::seedSet = true;
+ }
+ } else if (strcmp(argv[i], "-minimumvalue") == 0) {
+ if (i + 1 >= argc) {
+ printf("-minimumvalue needs an extra parameter to indicate the minimum time(ms)\n");
+ exit(1);
+ } else {
+ QBenchmarkGlobalData::current->walltimeMinimum = qToInt(argv[++i]);
+ }
+ } else if (strcmp(argv[i], "-iterations") == 0) {
+ if (i + 1 >= argc) {
+ printf("-iterations needs an extra parameter to indicate the number of iterations\n");
+ exit(1);
+ } else {
+ QBenchmarkGlobalData::current->iterationCount = qToInt(argv[++i]);
+ }
+ } else if (strcmp(argv[i], "-median") == 0) {
+ if (i + 1 >= argc) {
+ printf("-median needs an extra parameter to indicate the number of median iterations\n");
+ exit(1);
+ } else {
+ QBenchmarkGlobalData::current->medianIterationCount = qToInt(argv[++i]);
+ }
+
+ } else if (strcmp(argv[i], "-vb") == 0) {
+ QBenchmarkGlobalData::current->verboseOutput = true;
+ } else if (strcmp(argv[i], "-chart") == 0) {
+ fprintf(stderr, "Warning: `-chart' option is not available\n");
+ } else if (strcmp(argv[i], "-qws") == 0) {
+ // do nothing
+ } else if (strcmp(argv[i], "-graphicssystem") == 0) {
+ // do nothing
+ if (i + 1 >= argc) {
+ printf("-graphicssystem needs an extra parameter specifying the graphics system\n");
+ exit(1);
+ } else {
+ ++i;
+ }
+ } else if (argv[i][0] == '-') {
+ printf("Unknown option: '%s'\n\n%s", argv[i], testOptions);
+ exit(1);
+ } else if (qml) {
+ // We can't check the availability of test functions until
+ // we load the QML files. So just store the data for now.
+ int colon = -1;
+ int offset;
+ for(offset = 0; *(argv[i]+offset); ++offset) {
+ if (*(argv[i]+offset) == ':') {
+ if (*(argv[i]+offset+1) == ':') {
+ // "::" is used as a test name separator.
+ // e.g. "ClickTests::test_click:row1".
+ ++offset;
+ } else {
+ colon = offset;
+ break;
+ }
+ }
+ }
+ if (colon == -1) {
+ QTest::testFunctions += QString::fromLatin1(argv[i]);
+ QTest::testTags += QString();
+ } else {
+ QTest::testFunctions +=
+ QString::fromLatin1(argv[i], colon);
+ QTest::testTags +=
+ QString::fromLatin1(argv[i] + colon + 1);
+ }
+ } else {
+ if (!QTest::testFuncs) {
+ QTest::testFuncs = new QTest::TestFunction[512];
+ }
+
+ int colon = -1;
+ char buf[512], *data=0;
+ int off;
+ for(off = 0; *(argv[i]+off); ++off) {
+ if (*(argv[i]+off) == ':') {
+ colon = off;
+ break;
+ }
+ }
+ if(colon != -1) {
+ data = qstrdup(argv[i]+colon+1);
+ }
+ QTest::qt_snprintf(buf, qMin(512, off + 1), "%s", argv[i]); // copy text before the ':' into buf
+ QTest::qt_snprintf(buf + off, qMin(512 - off, 3), "()"); // append "()"
+ int idx = QTest::currentTestObject->metaObject()->indexOfMethod(buf);
+ if (idx < 0 || !isValidSlot(QTest::currentTestObject->metaObject()->method(idx))) {
+ printf("Unknown testfunction: '%s'\n", buf);
+ printf("Available testfunctions:\n");
+ qPrintTestSlots();
+ exit(1);
+ }
+ testFuncs[testFuncCount].set(idx, data);
+ testFuncCount++;
+ QTEST_ASSERT(QTest::testFuncCount < 512);
+ }
+ }
+
+ if (QTest::seedSet && !QTest::randomOrder) {
+ printf("-seed requires -random\n");
+ exit(1);
+ }
+}
+
+QBenchmarkResult qMedian(const QList<QBenchmarkResult> &container)
+{
+ const int count = container.count();
+ if (count == 0)
+ return QBenchmarkResult();
+
+ if (count == 1)
+ return container.at(0);
+
+ QList<QBenchmarkResult> containerCopy = container;
+ qSort(containerCopy);
+
+ const int middle = count / 2;
+
+ // ### handle even-sized containers here by doing an aritmetic mean of the two middle items.
+ return containerCopy.at(middle);
+}
+
+struct QTestDataSetter
+{
+ QTestDataSetter(QTestData *data)
+ {
+ QTestResult::setCurrentTestData(data);
+ }
+ ~QTestDataSetter()
+ {
+ QTestResult::setCurrentTestData(0);
+ }
+};
+
+static void qInvokeTestMethodDataEntry(char *slot)
+{
+ /* Benchmarking: for each median iteration*/
+
+ int i = (QBenchmarkGlobalData::current->measurer->needsWarmupIteration()) ? -1 : 0;
+
+ QList<QBenchmarkResult> results;
+ do {
+ QBenchmarkTestMethodData::current->beginDataRun();
+
+ /* Benchmarking: for each accumulation iteration*/
+ bool invokeOk;
+ do {
+ QTestResult::setCurrentTestLocation(QTestResult::InitFunc);
+ invokeMethod(QTest::currentTestObject, "init()");
+ if (QTestResult::skipCurrentTest())
+ break;
+
+ QTestResult::setCurrentTestLocation(QTestResult::Func);
+
+ QBenchmarkTestMethodData::current->result = QBenchmarkResult();
+ QBenchmarkTestMethodData::current->resultAccepted = false;
+
+ QBenchmarkGlobalData::current->context.tag =
+ QLatin1String(
+ QTestResult::currentDataTag()
+ ? QTestResult::currentDataTag() : "");
+
+ invokeOk = QMetaObject::invokeMethod(QTest::currentTestObject, slot,
+ Qt::DirectConnection);
+ if (!invokeOk)
+ QTestResult::addFailure("Unable to execute slot", __FILE__, __LINE__);
+
+ QTestResult::setCurrentTestLocation(QTestResult::CleanupFunc);
+ invokeMethod(QTest::currentTestObject, "cleanup()");
+ QTestResult::setCurrentTestLocation(QTestResult::NoWhere);
+
+ // If this test method has a benchmark, repeat until all measurements are
+ // acceptable.
+ // The QBENCHMARK macro increases the number of iterations for each run until
+ // this happens.
+ } while (invokeOk
+ && QBenchmarkTestMethodData::current->isBenchmark()
+ && QBenchmarkTestMethodData::current->resultsAccepted() == false);
+
+ QBenchmarkTestMethodData::current->endDataRun();
+ if (i > -1) // iteration -1 is the warmup iteration.
+ results.append(QBenchmarkTestMethodData::current->result);
+
+ if (QBenchmarkTestMethodData::current->isBenchmark() &&
+ QBenchmarkGlobalData::current->verboseOutput) {
+ if (i == -1) {
+ qDebug() << "warmup stage result :" << QBenchmarkTestMethodData::current->result.value;
+ } else {
+ qDebug() << "accumulation stage result:" << QBenchmarkTestMethodData::current->result.value;
+ }
+ }
+ } while (QBenchmarkTestMethodData::current->isBenchmark()
+ && (++i < QBenchmarkGlobalData::current->adjustMedianIterationCount()));
+
+ if (QBenchmarkTestMethodData::current->isBenchmark()
+ && QBenchmarkTestMethodData::current->resultsAccepted())
+ QTestLog::addBenchmarkResult(qMedian(results));
+}
+
+/*!
+ \internal
+
+ Call init(), slot_data(), slot(), slot(), slot()..., cleanup()
+ If data is set then it is the only test that is performed
+
+ If the function was successfully called, true is returned, otherwise
+ false.
+ */
+static bool qInvokeTestMethod(const char *slotName, const char *data=0)
+{
+ QTEST_ASSERT(slotName);
+
+ QBenchmarkTestMethodData benchmarkData;
+ QBenchmarkTestMethodData::current = &benchmarkData;
+
+ QBenchmarkGlobalData::current->context.slotName = QLatin1String(slotName);
+
+ char member[512];
+ QTestTable table;
+
+ char *slot = qstrdup(slotName);
+ slot[strlen(slot) - 2] = '\0';
+ QTestResult::setCurrentTestFunction(slot);
+
+ const QTestTable *gTable = QTestTable::globalTestTable();
+ const int globalDataCount = gTable->dataCount();
+ int curGlobalDataIndex = 0;
+
+ /* For each test function that has a *_data() table/function, do: */
+ do {
+ if (!gTable->isEmpty())
+ QTestResult::setCurrentGlobalTestData(gTable->testData(curGlobalDataIndex));
+
+ if (curGlobalDataIndex == 0) {
+ QTestResult::setCurrentTestLocation(QTestResult::DataFunc);
+ QTest::qt_snprintf(member, 512, "%s_data()", slot);
+ invokeMethod(QTest::currentTestObject, member);
+
+ // if we encounter a SkipAll in the _data slot, we skip the whole
+ // testfunction, no matter how much global data exists
+ if (QTestResult::skipCurrentTest()) {
+ QTestResult::setCurrentGlobalTestData(0);
+ break;
+ }
+ }
+
+ bool foundFunction = false;
+ if (!QTestResult::skipCurrentTest()) {
+ int curDataIndex = 0;
+ const int dataCount = table.dataCount();
+ QTestResult::setSkipCurrentTest(false);
+
+ // Data tag requested but none available?
+ if (data && !dataCount) {
+ // Let empty data tag through.
+ if (!*data)
+ data = 0;
+ else {
+ printf("Unknown testdata for function %s: '%s'\n", slotName, data);
+ printf("Function has no testdata.\n");
+ return false;
+ }
+ }
+
+ /* For each entry in the data table, do: */
+ do {
+ if (!data || !qstrcmp(data, table.testData(curDataIndex)->dataTag())) {
+ foundFunction = true;
+ QTestDataSetter s(curDataIndex >= dataCount ? static_cast<QTestData *>(0)
+ : table.testData(curDataIndex));
+
+ qInvokeTestMethodDataEntry(slot);
+
+ if (QTestResult::skipCurrentTest())
+ // check whether SkipAll was requested
+ break;
+ if (data)
+ break;
+ }
+ ++curDataIndex;
+ } while (curDataIndex < dataCount);
+ }
+
+ if (data && !foundFunction) {
+ printf("Unknown testdata for function %s: '%s'\n", slotName, data);
+ printf("Available testdata:\n");
+ for(int i = 0; i < table.dataCount(); ++i)
+ printf("%s\n", table.testData(i)->dataTag());
+ return false;
+ }
+
+ QTestResult::setCurrentGlobalTestData(0);
+ ++curGlobalDataIndex;
+ } while (curGlobalDataIndex < globalDataCount);
+
+ QTestResult::finishedCurrentTestFunction();
+ QTestResult::setSkipCurrentTest(false);
+ QTestResult::setCurrentTestData(0);
+ delete[] slot;
+
+ return true;
+}
+
+void *fetchData(QTestData *data, const char *tagName, int typeId)
+{
+ QTEST_ASSERT(typeId);
+ QTEST_ASSERT_X(data, "QTest::fetchData()", "Test data requested, but no testdata available.");
+ QTEST_ASSERT(data->parent());
+
+ int idx = data->parent()->indexOf(tagName);
+
+ if (idx == -1 || idx >= data->dataCount()) {
+ qFatal("QFETCH: Requested testdata '%s' not available, check your _data function.",
+ tagName);
+ }
+
+ if (typeId != data->parent()->elementTypeId(idx)) {
+ qFatal("Requested type '%s' does not match available type '%s'.",
+ QMetaType::typeName(typeId),
+ QMetaType::typeName(data->parent()->elementTypeId(idx)));
+ }
+
+ return data->data(idx);
+}
+
+/*!
+ \fn char* QTest::toHexRepresentation(const char *ba, int length)
+
+ Returns a pointer to a string that is the string \a ba represented
+ as a space-separated sequence of hex characters. If the input is
+ considered too long, it is truncated. A trucation is indicated in
+ the returned string as an ellipsis at the end.
+
+ \a length is the length of the string \a ba.
+ */
+char *toHexRepresentation(const char *ba, int length)
+{
+ if(length == 0)
+ return qstrdup("");
+
+ /* We output at maximum about maxLen characters in order to avoid
+ * running out of memory and flooding things when the byte array
+ * is large.
+ *
+ * maxLen can't be for example 200 because QTestLib is sprinkled with fixed
+ * size char arrays.
+ * */
+ const int maxLen = 50;
+ const int len = qMin(maxLen, length);
+ char *result = 0;
+
+ if(length > maxLen) {
+ const int size = len * 3 + 4;
+ result = new char[size];
+
+ char *const forElipsis = result + size - 5;
+ forElipsis[0] = ' ';
+ forElipsis[1] = '.';
+ forElipsis[2] = '.';
+ forElipsis[3] = '.';
+ result[size - 1] = '\0';
+ }
+ else {
+ const int size = len * 3;
+ result = new char[size];
+ result[size - 1] = '\0';
+ }
+
+ const char toHex[] = "0123456789ABCDEF";
+ int i = 0;
+ int o = 0;
+
+ while(true) {
+ const char at = ba[i];
+
+ result[o] = toHex[(at >> 4) & 0x0F];
+ ++o;
+ result[o] = toHex[at & 0x0F];
+
+ ++i;
+ ++o;
+ if(i == len)
+ break;
+ else {
+ result[o] = ' ';
+ ++o;
+ }
+ }
+
+ return result;
+}
+
+static void qInvokeTestMethods(QObject *testObject)
+{
+ const QMetaObject *metaObject = testObject->metaObject();
+ QTEST_ASSERT(metaObject);
+ if (QTest::randomOrder) {
+ QTestLog::startLogging(QTest::seed);
+ } else {
+ QTestLog::startLogging();
+ }
+ QTestResult::setCurrentTestFunction("initTestCase");
+ QTestResult::setCurrentTestLocation(QTestResult::DataFunc);
+ QTestTable::globalTestTable();
+ invokeMethod(testObject, "initTestCase_data()");
+
+ if (!QTestResult::skipCurrentTest() && !QTest::currentTestFailed()) {
+ QTestResult::setCurrentTestLocation(QTestResult::InitFunc);
+ invokeMethod(testObject, "initTestCase()");
+
+ // finishedCurrentTestFunction() resets QTestResult::testFailed(), so use a local copy.
+ const bool previousFailed = QTestResult::testFailed();
+ QTestResult::finishedCurrentTestFunction();
+
+ if(!QTestResult::skipCurrentTest() && !previousFailed) {
+
+ if (QTest::testFuncs) {
+ if (QTest::randomOrder)
+ randomizeList(QTest::testFuncs, QTest::testFuncCount);
+ for (int i = 0; i != QTest::testFuncCount; i++) {
+ if (!qInvokeTestMethod(metaObject->method(QTest::testFuncs[i].function()).signature(),
+ QTest::testFuncs[i].data())) {
+ break;
+ }
+ }
+ testFuncCleaner.cleanup();
+ } else {
+ int methodCount = metaObject->methodCount();
+ QMetaMethod *testMethods = new QMetaMethod[methodCount];
+ for (int i = 0; i != methodCount; i++)
+ testMethods[i] = metaObject->method(i);
+ if (QTest::randomOrder)
+ randomizeList(testMethods, methodCount);
+ for (int i = 0; i != methodCount; i++) {
+ if (!isValidSlot(testMethods[i]))
+ continue;
+ if (!qInvokeTestMethod(testMethods[i].signature()))
+ break;
+ }
+ delete[] testMethods;
+ testMethods = 0;
+ }
+ }
+
+ QTestResult::setSkipCurrentTest(false);
+ QTestResult::setCurrentTestFunction("cleanupTestCase");
+ invokeMethod(testObject, "cleanupTestCase()");
+ }
+ QTestResult::finishedCurrentTestFunction();
+ QTestResult::setCurrentTestFunction(0);
+ QTestTable::clearGlobalTestTable();
+
+ QTestLog::stopLogging();
+}
+
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+class FatalSignalHandler
+{
+public:
+ FatalSignalHandler();
+ ~FatalSignalHandler();
+
+private:
+ static void signal(int);
+ sigset_t handledSignals;
+};
+
+void FatalSignalHandler::signal(int signum)
+{
+ qFatal("Received signal %d", signum);
+#if defined(Q_OS_INTEGRITY)
+ {
+ struct sigaction act;
+ memset(&act, 0, sizeof(struct sigaction));
+ act.sa_handler = SIG_DFL;
+ sigaction(signum, &act, NULL);
+ }
+#endif
+}
+
+FatalSignalHandler::FatalSignalHandler()
+{
+ sigemptyset(&handledSignals);
+
+ const int fatalSignals[] = {
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, 0 };
+
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = FatalSignalHandler::signal;
+
+ // Remove the handler after it is invoked.
+#if !defined(Q_OS_INTEGRITY)
+ act.sa_flags = SA_RESETHAND;
+#endif
+ // Block all fatal signals in our signal handler so we don't try to close
+ // the testlog twice.
+ sigemptyset(&act.sa_mask);
+ for (int i = 0; fatalSignals[i]; ++i)
+ sigaddset(&act.sa_mask, fatalSignals[i]);
+
+ struct sigaction oldact;
+
+ for (int i = 0; fatalSignals[i]; ++i) {
+ sigaction(fatalSignals[i], &act, &oldact);
+#ifndef Q_WS_QWS
+ // Don't overwrite any non-default handlers
+ // however, we need to replace the default QWS handlers
+ if (
+#ifdef SA_SIGINFO
+ oldact.sa_flags & SA_SIGINFO ||
+#endif
+ oldact.sa_handler != SIG_DFL) {
+ sigaction(fatalSignals[i], &oldact, 0);
+ } else
+#endif
+ {
+ sigaddset(&handledSignals, fatalSignals[i]);
+ }
+ }
+}
+
+
+FatalSignalHandler::~FatalSignalHandler()
+{
+ // Unregister any of our remaining signal handlers
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_DFL;
+
+ struct sigaction oldact;
+
+ for (int i = 1; i < 32; ++i) {
+ if (!sigismember(&handledSignals, i))
+ continue;
+ sigaction(i, &act, &oldact);
+
+ // If someone overwrote it in the mean time, put it back
+ if (oldact.sa_handler != FatalSignalHandler::signal)
+ sigaction(i, &oldact, 0);
+ }
+}
+
+#endif
+
+
+} // namespace
+
+/*!
+ Executes tests declared in \a testObject. In addition, the private slots
+ \c{initTestCase()}, \c{cleanupTestCase()}, \c{init()} and \c{cleanup()}
+ are executed if they exist. See \l{Creating a Test} for more details.
+
+ Optionally, the command line arguments \a argc and \a argv can be provided.
+ For a list of recognized arguments, read \l {QTestLib Command Line Arguments}.
+
+ For stand-alone tests, the convenience macro \l QTEST_MAIN() can
+ be used to declare a main method that parses the command line arguments
+ and executes the tests.
+
+ Returns 0 if all tests passed. Returns a value other than 0 if tests failed
+ or in case of unhandled exceptions. The return value from this function is
+ also the exit code of the test application when the \l QTEST_MAIN() macro
+ is used.
+
+ The following example will run all tests in \c MyFirstTestObject and
+ \c{MySecondTestObject}:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 18
+
+ Note: This function is not reentrant, only one test can run at a time. A
+ test that was executed with qExec() can't run another test via qExec() and
+ threads are not allowed to call qExec() simultaneously.
+
+ If you have programatically created the arguments, as opposed to getting them
+ from the arguments in \c main(), it is likely of interest to use
+ QTest::qExec(QObject *, const QStringList &) since it is Unicode safe.
+
+ \sa QTEST_MAIN()
+*/
+
+int QTest::qExec(QObject *testObject, int argc, char **argv)
+{
+ QBenchmarkGlobalData benchmarkData;
+ QBenchmarkGlobalData::current = &benchmarkData;
+
+#ifdef QTESTLIB_USE_VALGRIND
+ int callgrindChildExitCode = 0;
+#endif
+
+#ifdef Q_WS_MAC
+ bool macNeedsActivate = qApp && (qstrcmp(qApp->metaObject()->className(), "QApplication") == 0);
+#ifdef QT_MAC_USE_COCOA
+ IOPMAssertionID powerID;
+#endif
+#endif
+#ifndef QT_NO_EXCEPTIONS
+ try {
+#endif
+
+ #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);
+ #endif
+
+#ifdef Q_WS_MAC
+ // Starting with Qt 4.4, applications launched from the command line
+ // no longer get focus automatically. Since some tests might depend
+ // on this, call SetFrontProcess here to get the pre 4.4 behavior.
+ if (macNeedsActivate) {
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+ SetFrontProcess(&psn);
+# ifdef QT_MAC_USE_COCOA
+ IOReturn ok = IOPMAssertionCreate(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, &powerID);
+ if (ok != kIOReturnSuccess)
+ macNeedsActivate = false; // no need to release the assertion on exit.
+# else
+ UpdateSystemActivity(1); // Wake the display.
+# endif
+ }
+#endif
+
+#if defined(Q_OS_SYMBIAN) && defined(Q_CC_NOKIAX86)
+ // Delay execution of tests in Symbian emulator.
+ // Needed to allow worst of other higher priority apps and services launched by emulator
+ // to get out of the way before we run our test. Otherwise some of the timing sensitive tests
+ // will not work properly.
+ qSleep(3000);
+#endif
+
+ QTestResult::reset();
+
+ QTEST_ASSERT(testObject);
+ QTEST_ASSERT(!currentTestObject);
+ currentTestObject = testObject;
+
+ const QMetaObject *metaObject = testObject->metaObject();
+ QTEST_ASSERT(metaObject);
+
+ QTestResult::setCurrentTestObject(metaObject->className());
+ qtest_qParseArgs(argc, argv, false);
+ if (QTest::randomOrder) {
+ seedRandom();
+ }
+#ifdef QTESTLIB_USE_VALGRIND
+ if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) {
+ const QStringList origAppArgs(QCoreApplication::arguments());
+ if (!QBenchmarkValgrindUtils::rerunThroughCallgrind(origAppArgs, callgrindChildExitCode))
+ return -1;
+
+ QBenchmarkValgrindUtils::cleanup();
+
+ } else
+#endif
+ {
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ QScopedPointer<FatalSignalHandler> handler;
+ if (!noCrashHandler)
+ handler.reset(new FatalSignalHandler);
+#endif
+ qInvokeTestMethods(testObject);
+ }
+
+#ifndef QT_NO_EXCEPTIONS
+ } catch (...) {
+ QTestResult::addFailure("Caught unhandled exception", __FILE__, __LINE__);
+ if (QTestResult::currentTestFunction()) {
+ QTestResult::finishedCurrentTestFunction();
+ QTestResult::setCurrentTestFunction(0);
+ }
+
+ QTestLog::stopLogging();
+#ifdef QT_MAC_USE_COCOA
+ if (macNeedsActivate) {
+ IOPMAssertionRelease(powerID);
+ }
+#endif
+ currentTestObject = 0;
+
+ // Rethrow exception to make debugging easier.
+ throw;
+ return 1;
+ }
+# endif
+
+ currentTestObject = 0;
+#ifdef QT_MAC_USE_COCOA
+ if (macNeedsActivate) {
+ IOPMAssertionRelease(powerID);
+ }
+#endif
+
+#if defined(QTEST_NOEXITCODE)
+ return 0;
+#else
+
+#ifdef QTESTLIB_USE_VALGRIND
+ if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess)
+ return callgrindChildExitCode;
+#endif
+ // make sure our exit code is never going above 127
+ // since that could wrap and indicate 0 test fails
+ return qMin(QTestResult::failCount(), 127);
+
+#endif
+}
+
+/*!
+ \overload
+ \since 4.4
+
+ Behaves identically to qExec(QObject *, int, char**) but takes a
+ QStringList of \a arguments instead of a \c char** list.
+ */
+int QTest::qExec(QObject *testObject, const QStringList &arguments)
+{
+ const int argc = arguments.count();
+ QVarLengthArray<char *> argv(argc);
+
+ QVector<QByteArray> args;
+ args.reserve(argc);
+
+ for(int i = 0; i < argc; ++i)
+ {
+ args.append(arguments.at(i).toLocal8Bit().constData());
+ argv[i] = args.last().data();
+ }
+
+ return qExec(testObject, argc, argv.data());
+}
+
+/*! \internal
+ */
+void QTest::qFail(const char *statementStr, const char *file, int line)
+{
+ QTestResult::addFailure(statementStr, file, line);
+}
+
+/*! \internal
+ */
+bool QTest::qVerify(bool statement, const char *statementStr, const char *description,
+ const char *file, int line)
+{
+ return QTestResult::verify(statement, statementStr, description, file, line);
+}
+
+/*! \fn void QTest::qSkip(const char *message, SkipMode mode, const char *file, int line)
+\internal
+ */
+void QTest::qSkip(const char *message, QTest::SkipMode mode,
+ const char *file, int line)
+{
+ QTestResult::addSkip(message, mode, file, line);
+ if (mode == QTest::SkipAll)
+ QTestResult::setSkipCurrentTest(true);
+}
+
+/*! \fn bool QTest::qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode, const char *file, int line)
+\internal
+ */
+bool QTest::qExpectFail(const char *dataIndex, const char *comment,
+ QTest::TestFailMode mode, const char *file, int line)
+{
+ return QTestResult::expectFail(dataIndex, qstrdup(comment), mode, file, line);
+}
+
+/*! \internal
+ */
+void QTest::qWarn(const char *message)
+{
+ QTestLog::warn(message);
+}
+
+/*!
+ Ignores messages created by qDebug() or qWarning(). If the \a message
+ 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.
+
+ \bold {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.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 19
+
+ The example above tests that QDir::mkdir() outputs the right warning when invoked
+ with an invalid file name.
+*/
+void QTest::ignoreMessage(QtMsgType type, const char *message)
+{
+ QTestResult::ignoreMessage(type, message);
+}
+
+/*! \internal
+ */
+void *QTest::qData(const char *tagName, int typeId)
+{
+ return fetchData(QTestResult::currentTestData(), tagName, typeId);
+}
+
+/*! \internal
+ */
+void *QTest::qGlobalData(const char *tagName, int typeId)
+{
+ return fetchData(QTestResult::currentGlobalTestData(), tagName, typeId);
+}
+
+/*! \internal
+ */
+void *QTest::qElementData(const char *tagName, int metaTypeId)
+{
+ QTEST_ASSERT(tagName);
+ QTestData *data = QTestResult::currentTestData();
+ QTEST_ASSERT(data);
+ QTEST_ASSERT(data->parent());
+
+ int idx = data->parent()->indexOf(tagName);
+ QTEST_ASSERT(idx != -1);
+ QTEST_ASSERT(data->parent()->elementTypeId(idx) == metaTypeId);
+
+ return data->data(data->parent()->indexOf(tagName));
+}
+
+/*! \internal
+ */
+void QTest::addColumnInternal(int id, const char *name)
+{
+ QTestTable *tbl = QTestTable::currentTestTable();
+ QTEST_ASSERT_X(tbl, "QTest::addColumn()", "Cannot add testdata outside of a _data slot.");
+
+ tbl->addColumn(id, name);
+}
+
+/*!
+ Appends a new row to the current test data. \a dataTag is the name of
+ the testdata that will appear in the test output. Returns a QTestData reference
+ that can be used to stream in data.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 20
+
+ \bold {Note:} This macro can only be used in a test's data function
+ that is invoked by the test framework.
+
+ See \l {Chapter 2: Data Driven Testing}{Data Driven Testing} for
+ a more extensive example.
+
+ \sa addColumn(), QFETCH()
+*/
+QTestData &QTest::newRow(const char *dataTag)
+{
+ QTestTable *tbl = QTestTable::currentTestTable();
+ QTEST_ASSERT_X(tbl, "QTest::addColumn()", "Cannot add testdata outside of a _data slot.");
+
+ return *tbl->newData(dataTag);
+}
+
+/*! \fn void QTest::addColumn(const char *name, T *dummy = 0)
+
+ Adds a column with type \c{T} to the current test data.
+ \a name is the name of the column. \a dummy is a workaround
+ for buggy compilers and can be ignored.
+
+ To populate the column with values, newRow() can be used. Use
+ \l QFETCH() to fetch the data in the actual test.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 21
+
+ To add custom types to the testdata, the type must be registered with
+ QMetaType via \l Q_DECLARE_METATYPE().
+
+ \bold {Note:} This macro can only be used in a test's data function
+ that is invoked by the test framework.
+
+ See \l {Chapter 2: Data Driven Testing}{Data Driven Testing} for
+ a more extensive example.
+
+ \sa QTest::newRow(), QFETCH(), QMetaType
+*/
+
+/*!
+ Returns the name of the test function that is currently executed.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 22
+*/
+const char *QTest::currentTestFunction()
+{
+ return QTestResult::currentTestFunction();
+}
+
+/*!
+ Returns the name of the current test data. If the test doesn't
+ have any assigned testdata, the function returns 0.
+*/
+const char *QTest::currentDataTag()
+{
+ return QTestResult::currentDataTag();
+}
+
+/*!
+ Returns true if the current test function failed, otherwise false.
+*/
+bool QTest::currentTestFailed()
+{
+ return QTestResult::currentTestFailed();
+}
+
+/*!
+ Sleeps for \a ms milliseconds, blocking execution of the
+ test. qSleep() will not do any event processing and leave your test
+ unresponsive. Network communication might time out while
+ sleeping. Use \l qWait() to do non-blocking sleeping.
+
+ \a ms must be greater than 0.
+
+ \bold {Note:} The qSleep() function calls either \c nanosleep() on
+ unix or \c Sleep() on windows, so the accuracy of time spent in
+ qSleep() depends on the operating system.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 23
+
+ \sa qWait()
+*/
+void QTest::qSleep(int ms)
+{
+ QTEST_ASSERT(ms > 0);
+
+#ifdef Q_OS_WIN
+ Sleep(uint(ms));
+#else
+ struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
+ nanosleep(&ts, NULL);
+#endif
+}
+
+/*! \internal
+ */
+QObject *QTest::testObject()
+{
+ return currentTestObject;
+}
+
+/*! \internal
+ */
+bool QTest::compare_helper(bool success, const char *msg, const char *file, int line)
+{
+ return QTestResult::compare(success, msg, file, line);
+}
+
+/*! \internal
+ */
+bool QTest::compare_helper(bool success, const char *msg, char *val1, char *val2,
+ const char *actual, const char *expected, const char *file, int line)
+{
+ return QTestResult::compare(success, msg, val1, val2, actual, expected, file, line);
+}
+
+/*! \fn bool QTest::qCompare<float>(float const &t1, float const &t2, const char *actual, const char *expected, const char *file, int line)
+\internal
+ */
+template <>
+Q_TESTLIB_EXPORT bool QTest::qCompare<float>(float const &t1, float const &t2, const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return qFuzzyCompare(t1, t2)
+ ? compare_helper(true, "COMPARE()", file, line)
+ : compare_helper(false, "Compared floats are not the same (fuzzy compare)",
+ toString(t1), toString(t2), actual, expected, file, line);
+}
+
+/*! \fn bool QTest::qCompare<double>(double const &t1, double const &t2, const char *actual, const char *expected, const char *file, int line)
+\internal
+ */
+template <>
+Q_TESTLIB_EXPORT bool QTest::qCompare<double>(double const &t1, double const &t2, const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return qFuzzyCompare(t1, t2)
+ ? compare_helper(true, "COMPARE()", file, line)
+ : compare_helper(false, "Compared doubles are not the same (fuzzy compare)",
+ toString(t1), toString(t2), actual, expected, file, line);
+}
+
+#define COMPARE_IMPL2(TYPE, FORMAT) \
+template <> Q_TESTLIB_EXPORT char *QTest::toString<TYPE >(const TYPE &t) \
+{ \
+ char *msg = new char[128]; \
+ qt_snprintf(msg, 128, #FORMAT, t); \
+ return msg; \
+}
+
+COMPARE_IMPL2(short, %hd)
+COMPARE_IMPL2(ushort, %hu)
+COMPARE_IMPL2(int, %d)
+COMPARE_IMPL2(uint, %u)
+COMPARE_IMPL2(long, %ld)
+COMPARE_IMPL2(ulong, %lu)
+#if defined(Q_OS_WIN)
+COMPARE_IMPL2(qint64, %I64d)
+COMPARE_IMPL2(quint64, %I64u)
+#else
+COMPARE_IMPL2(qint64, %lld)
+COMPARE_IMPL2(quint64, %llu)
+#endif
+COMPARE_IMPL2(bool, %d)
+COMPARE_IMPL2(char, %c)
+COMPARE_IMPL2(float, %g)
+COMPARE_IMPL2(double, %lg)
+
+/*! \internal
+ */
+char *QTest::toString(const char *str)
+{
+ if (!str)
+ return 0;
+ char *msg = new char[strlen(str) + 1];
+ return qstrcpy(msg, str);
+}
+
+/*! \internal
+ */
+char *QTest::toString(const void *p)
+{
+ char *msg = new char[128];
+ qt_snprintf(msg, 128, "%p", p);
+ return msg;
+}
+
+/*! \internal
+ */
+bool QTest::compare_string_helper(const char *t1, const char *t2, const char *actual,
+ const char *expected, const char *file, int line)
+{
+ return (qstrcmp(t1, t2) == 0)
+ ? compare_helper(true, "COMPARE()", file, line)
+ : compare_helper(false, "Compared strings are not the same",
+ toString(t1), toString(t2), actual, expected, file, line);
+}
+
+/*! \fn bool QTest::compare_ptr_helper(const void *t1, const void *t2, const char *actual, const char *expected, const char *file, int line);
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(T1 const &, T2 const &, const char *, const char *, const char *, int);
+ \internal
+*/
+
+
+/*! \fn void QTest::mouseEvent(MouseAction action, QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(QIcon const &t1, QIcon const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(QPixmap const &t1, QPixmap const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(T const &t1, T const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(const T *t1, const T *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(T *t1, T *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(const T1 *t1, const T2 *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(T1 *t1, T2 *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(const char *t1, const char *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(char *t1, char *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(char *t1, const char *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(const char *t1, char *t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(QString const &t1, QLatin1String const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(QLatin1String const &t1, QString const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(QStringList const &t1, QStringList const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(QFlags<T> const &t1, T const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(QFlags<T> const &t1, int const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn bool QTest::qCompare(bool const &t1, int const &t2, const char *actual, const char *expected, const char *file, int line)
+ \internal
+ */
+
+/*! \fn bool QTest::qTest(const T& actual, const char *elementName, const char *actualStr, const char *expected, const char *file, int line)
+ \internal
+*/
+
+/*! \fn void QTest::sendKeyEvent(KeyAction action, QWidget *widget, Qt::Key code, QString text, Qt::KeyboardModifiers modifier, int delay=-1)
+ \internal
+*/
+
+/*! \fn void QTest::sendKeyEvent(KeyAction action, QWidget *widget, Qt::Key code, char ascii, Qt::KeyboardModifiers modifier, int delay=-1)
+ \internal
+*/
+
+/*! \fn void QTest::simulateEvent(QWidget *widget, bool press, int code, Qt::KeyboardModifiers modifier, QString text, bool repeat, int delay=-1)
+ \internal
+*/
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
new file mode 100644
index 0000000000..a2cc26de98
--- /dev/null
+++ b/src/testlib/qtestcase.h
@@ -0,0 +1,375 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTCASE_H
+#define QTESTCASE_H
+
+#include <QtTest/qtest_global.h>
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+#define QVERIFY(statement) \
+do {\
+ if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__))\
+ return;\
+} while (0)
+
+#define QFAIL(message) \
+do {\
+ QTest::qFail(message, __FILE__, __LINE__);\
+ return;\
+} while (0)
+
+#define QVERIFY2(statement, description) \
+do {\
+ if (statement) {\
+ if (!QTest::qVerify(true, #statement, (description), __FILE__, __LINE__))\
+ return;\
+ } else {\
+ if (!QTest::qVerify(false, #statement, (description), __FILE__, __LINE__))\
+ return;\
+ }\
+} while (0)
+
+#define QCOMPARE(actual, expected) \
+do {\
+ if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\
+ return;\
+} while (0)
+
+#define QSKIP(statement, mode) \
+do {\
+ QTest::qSkip(statement, QTest::mode, __FILE__, __LINE__);\
+ return;\
+} while (0)
+
+#define QEXPECT_FAIL(dataIndex, comment, mode)\
+do {\
+ if (!QTest::qExpectFail(dataIndex, comment, QTest::mode, __FILE__, __LINE__))\
+ return;\
+} while (0)
+
+#define QFETCH(type, name)\
+ type name = *static_cast<type *>(QTest::qData(#name, ::qMetaTypeId<type >()))
+
+#define QFETCH_GLOBAL(type, name)\
+ type name = *static_cast<type *>(QTest::qGlobalData(#name, ::qMetaTypeId<type >()))
+
+#define DEPENDS_ON(funcName)
+
+#define QTEST(actual, testElement)\
+do {\
+ if (!QTest::qTest(actual, testElement, #actual, #testElement, __FILE__, __LINE__))\
+ return;\
+} while (0)
+
+#define QWARN(msg)\
+ QTest::qWarn(msg)
+
+class QObject;
+class QTestData;
+
+#define QTEST_COMPARE_DECL(KLASS)\
+ template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
+
+namespace QTest
+{
+ template <typename T>
+ inline char *toString(const T &)
+ {
+ return 0;
+ }
+
+
+ Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, int length);
+ Q_TESTLIB_EXPORT char *toString(const char *);
+ Q_TESTLIB_EXPORT char *toString(const void *);
+
+ Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = 0);
+ Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments);
+
+ Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description,
+ const char *file, int line);
+ Q_TESTLIB_EXPORT void qFail(const char *statementStr, const char *file, int line);
+ Q_TESTLIB_EXPORT void qSkip(const char *message, SkipMode mode, const char *file, int line);
+ Q_TESTLIB_EXPORT bool qExpectFail(const char *dataIndex, const char *comment, TestFailMode mode,
+ const char *file, int line);
+ Q_TESTLIB_EXPORT void qWarn(const char *message);
+ Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message);
+
+ Q_TESTLIB_EXPORT void *qData(const char *tagName, int typeId);
+ Q_TESTLIB_EXPORT void *qGlobalData(const char *tagName, int typeId);
+ Q_TESTLIB_EXPORT void *qElementData(const char *elementName, int metaTypeId);
+ Q_TESTLIB_EXPORT QObject *testObject();
+
+ Q_TESTLIB_EXPORT const char *currentTestFunction();
+ Q_TESTLIB_EXPORT const char *currentDataTag();
+ Q_TESTLIB_EXPORT bool currentTestFailed();
+
+ Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii);
+ Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key);
+
+ Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *msg, const char *file,
+ int line);
+ Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *msg, char *val1, char *val2,
+ const char *expected, const char *actual,
+ const char *file, int line);
+ Q_TESTLIB_EXPORT void qSleep(int ms);
+ Q_TESTLIB_EXPORT void addColumnInternal(int id, const char *name);
+
+ template <typename T>
+ inline void addColumn(const char *name, T * = 0)
+ {
+ addColumnInternal(qMetaTypeId<T>(), name);
+ }
+ Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag);
+
+ template <typename T>
+ inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return (t1 == t2)
+ ? compare_helper(true, "COMPARE()", file, line)
+ : compare_helper(false, "Compared values are not the same",
+ toString<T>(t1), toString<T>(t2), actual, expected, file, line);
+ }
+
+
+ template <>
+ Q_TESTLIB_EXPORT bool qCompare<float>(float const &t1, float const &t2,
+ const char *actual, const char *expected, const char *file, int line);
+
+ template <>
+ Q_TESTLIB_EXPORT bool qCompare<double>(double const &t1, double const &t2,
+ const char *actual, const char *expected, const char *file, int line);
+
+ inline bool compare_ptr_helper(const void *t1, const void *t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return (t1 == t2)
+ ? compare_helper(true, "COMPARE()", file, line)
+ : compare_helper(false, "Compared pointers are not the same",
+ toString(t1), toString(t2), actual, expected, file, line);
+ }
+
+ Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
+ const char *expected, const char *file, int line);
+
+#ifndef qdoc
+ QTEST_COMPARE_DECL(short)
+ QTEST_COMPARE_DECL(ushort)
+ QTEST_COMPARE_DECL(int)
+ QTEST_COMPARE_DECL(uint)
+ QTEST_COMPARE_DECL(long)
+ QTEST_COMPARE_DECL(ulong)
+ QTEST_COMPARE_DECL(qint64)
+ QTEST_COMPARE_DECL(quint64)
+
+ QTEST_COMPARE_DECL(float)
+ QTEST_COMPARE_DECL(double)
+ QTEST_COMPARE_DECL(char)
+ QTEST_COMPARE_DECL(bool)
+#endif
+
+#ifndef QTEST_NO_SPECIALIZATIONS
+ template <typename T1, typename T2>
+ bool qCompare(T1 const &, T2 const &, const char *, const char *, const char *, int);
+
+#if defined(QT_COORD_TYPE) && (defined(QT_ARCH_ARM) || defined(QT_NO_FPU) || defined(QT_ARCH_WINDOWSCE))
+ template <>
+ inline bool qCompare<qreal, float>(qreal const &t1, float const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return qCompare<qreal>(t1, qreal(t2), actual, expected, file, line);
+ }
+
+ template <>
+ inline bool qCompare<float, qreal>(float const &t1, qreal const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return qCompare<qreal>(qreal(t1), t2, actual, expected, file, line);
+ }
+
+#elif defined(QT_COORD_TYPE) || defined(QT_ARCH_ARM) || defined(QT_NO_FPU) || defined(QT_ARCH_WINDOWSCE) || defined(QT_ARCH_SYMBIAN)
+ template <>
+ inline bool qCompare<qreal, double>(qreal const &t1, double const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return qCompare<float>(float(t1), float(t2), actual, expected, file, line);
+ }
+
+ template <>
+ inline bool qCompare<double, qreal>(double const &t1, qreal const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return qCompare<float>(float(t1), float(t2), actual, expected, file, line);
+ }
+
+#endif
+
+ template <typename T>
+ inline bool qCompare(const T *t1, const T *t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return compare_ptr_helper(t1, t2, actual, expected, file, line);
+ }
+ template <typename T>
+ inline bool qCompare(T *t1, T *t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return compare_ptr_helper(t1, t2, actual, expected, file, line);
+ }
+
+ template <typename T1, typename T2>
+ inline bool qCompare(const T1 *t1, const T2 *t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return compare_ptr_helper(t1, static_cast<const T1 *>(t2), actual, expected, file, line);
+ }
+ template <typename T1, typename T2>
+ inline bool qCompare(T1 *t1, T2 *t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return compare_ptr_helper(const_cast<const T1 *>(t1),
+ static_cast<const T1 *>(const_cast<const T2 *>(t2)), actual, expected, file, line);
+ }
+ template<>
+ inline bool qCompare<char>(const char *t1, const char *t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return compare_string_helper(t1, t2, actual, expected, file, line);
+ }
+ template<>
+ inline bool qCompare<char>(char *t1, char *t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return compare_string_helper(t1, t2, actual, expected, file, line);
+ }
+#else /* QTEST_NO_SPECIALIZATIONS */
+
+// In Symbian we have QTEST_NO_SPECIALIZATIONS defined, but still float related specialization
+// should be used. If QTEST_NO_SPECIALIZATIONS is enabled we get ambiguous overload errors.
+#if defined(QT_ARCH_SYMBIAN)
+ template <typename T1, typename T2>
+ bool qCompare(T1 const &, T2 const &, const char *, const char *, const char *, int);
+
+ template <>
+ inline bool qCompare<qreal, double>(qreal const &t1, double const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return qCompare<float>(float(t1), float(t2), actual, expected, file, line);
+ }
+
+ template <>
+ inline bool qCompare<double, qreal>(double const &t1, qreal const &t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return qCompare<float>(float(t1), float(t2), actual, expected, file, line);
+ }
+#endif
+
+ inline bool qCompare(const char *t1, const char *t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return compare_string_helper(t1, t2, actual, expected, file, line);
+ }
+
+ inline bool qCompare(char *t1, char *t2, const char *actual, const char *expected,
+ const char *file, int line)
+ {
+ return compare_string_helper(t1, t2, actual, expected, file, line);
+ }
+#endif
+
+ /* The next two specializations are for MSVC that shows problems with implicit
+ conversions
+ */
+#ifndef QTEST_NO_SPECIALIZATIONS
+ template<>
+#endif
+ inline bool qCompare(char *t1, const char *t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return compare_string_helper(t1, t2, actual, expected, file, line);
+ }
+#ifndef QTEST_NO_SPECIALIZATIONS
+ template<>
+#endif
+ inline bool qCompare(const char *t1, char *t2, const char *actual,
+ const char *expected, const char *file, int line)
+ {
+ return compare_string_helper(t1, t2, actual, expected, file, line);
+ }
+
+ // NokiaX86 and RVCT do not like implicitly comparing bool with int
+#ifndef QTEST_NO_SPECIALIZATIONS
+ template <>
+#endif
+ inline bool qCompare(bool const &t1, int const &t2,
+ const char *actual, const char *expected, const char *file, int line)
+ {
+ return qCompare<int>(int(t1), t2, actual, expected, file, line);
+ }
+
+
+ template <class T>
+ inline bool qTest(const T& actual, const char *elementName, const char *actualStr,
+ const char *expected, const char *file, int line)
+ {
+ return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName,
+ qMetaTypeId<T>())), actualStr, expected, file, line);
+ }
+}
+
+#undef QTEST_COMPARE_DECL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestcoreelement.h b/src/testlib/qtestcoreelement.h
new file mode 100644
index 0000000000..20b6208acd
--- /dev/null
+++ b/src/testlib/qtestcoreelement.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTCOREELEMENT_H
+#define QTESTCOREELEMENT_H
+
+#include <QtTest/qtestcorelist.h>
+#include <QtTest/qtestelementattribute.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+template <class ElementType>
+class QTestCoreElement: public QTestCoreList<ElementType>
+{
+ public:
+ QTestCoreElement( int type = -1 );
+ virtual ~QTestCoreElement();
+
+ void addAttribute(const QTest::AttributeIndex index, const char *value);
+ QTestElementAttribute *attributes() const;
+ const char *attributeValue(QTest::AttributeIndex index) const;
+ const char *attributeName(QTest::AttributeIndex index) const;
+ const QTestElementAttribute *attribute(QTest::AttributeIndex index) const;
+
+ const char *elementName() const;
+ QTest::LogElementType elementType() const;
+
+ private:
+ QTestElementAttribute *listOfAttributes;
+ QTest::LogElementType type;
+};
+
+template<class ElementType>
+QTestCoreElement<ElementType>::QTestCoreElement(int t)
+ :listOfAttributes(0), type(QTest::LogElementType(t))
+{
+}
+
+template<class ElementType>
+QTestCoreElement<ElementType>::~QTestCoreElement()
+{
+ delete listOfAttributes;
+}
+
+template <class ElementType>
+void QTestCoreElement<ElementType>::addAttribute(const QTest::AttributeIndex attributeIndex, const char *value)
+{
+ if(attributeIndex == -1)
+ return;
+
+ if (attribute(attributeIndex))
+ return;
+
+ QTestElementAttribute *testAttribute = new QTestElementAttribute;
+ testAttribute->setPair(attributeIndex, value);
+ testAttribute->addToList(&listOfAttributes);
+}
+
+template <class ElementType>
+QTestElementAttribute *QTestCoreElement<ElementType>::attributes() const
+{
+ return listOfAttributes;
+}
+
+template <class ElementType>
+const char *QTestCoreElement<ElementType>::attributeValue(QTest::AttributeIndex index) const
+{
+ const QTestElementAttribute *attrb = attribute(index);
+ if(attrb)
+ return attrb->value();
+
+ return 0;
+}
+
+template <class ElementType>
+const char *QTestCoreElement<ElementType>::attributeName(QTest::AttributeIndex index) const
+{
+ const QTestElementAttribute *attrb = attribute(index);
+ if(attrb)
+ return attrb->name();
+
+ return 0;
+}
+
+template <class ElementType>
+const char *QTestCoreElement<ElementType>::elementName() const
+{
+ const char *xmlElementNames[] =
+ {
+ "property",
+ "properties",
+ "failure",
+ "error",
+ "testcase",
+ "testsuite",
+ "benchmark",
+ "system-err"
+ };
+
+ if(type != QTest::LET_Undefined)
+ return xmlElementNames[type];
+
+ return 0;
+}
+
+template <class ElementType>
+QTest::LogElementType QTestCoreElement<ElementType>::elementType() const
+{
+ return type;
+}
+
+template <class ElementType>
+const QTestElementAttribute *QTestCoreElement<ElementType>::attribute(QTest::AttributeIndex index) const
+{
+ QTestElementAttribute *iterator = listOfAttributes;
+ while(iterator){
+ if(iterator->index() == index)
+ return iterator;
+
+ iterator = iterator->nextElement();
+ }
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestcorelist.h b/src/testlib/qtestcorelist.h
new file mode 100644
index 0000000000..4a88a6caa8
--- /dev/null
+++ b/src/testlib/qtestcorelist.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTCORELIST_H
+#define QTESTCORELIST_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+template <class T>
+class QTestCoreList
+{
+ public:
+ QTestCoreList();
+ virtual ~QTestCoreList();
+
+ void addToList(T **list);
+ T *nextElement();
+ T *previousElement();
+ int count(T *list);
+ int count();
+
+ private:
+ T *next;
+ T *prev;
+};
+
+template <class T>
+QTestCoreList<T>::QTestCoreList()
+:next(0)
+,prev(0)
+{
+}
+
+template <class T>
+QTestCoreList<T>::~QTestCoreList()
+{
+ if (prev) {
+ prev->next = 0;
+ }
+ delete prev;
+
+ if (next) {
+ next->prev = 0;
+ }
+ delete next;
+}
+
+template <class T>
+void QTestCoreList<T>::addToList(T **list)
+{
+ if (next)
+ next->addToList(list);
+ else {
+ next = *list;
+ if (next)
+ next->prev = static_cast<T*>(this);
+ }
+
+ *list = static_cast<T*>(this);
+}
+
+template <class T>
+T *QTestCoreList<T>::nextElement()
+{
+ return next;
+}
+
+template <class T>
+T *QTestCoreList<T>::previousElement()
+{
+ return prev;
+}
+
+template <class T>
+int QTestCoreList<T>::count()
+{
+ int numOfElements = 0;
+ T *it = next;
+
+ while(it){
+ ++numOfElements;
+ it = it->nextElement();
+ }
+
+ return numOfElements;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestdata.cpp b/src/testlib/qtestdata.cpp
new file mode 100644
index 0000000000..588ad64a3a
--- /dev/null
+++ b/src/testlib/qtestdata.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qmetaobject.h>
+
+#include "QtTest/qtestassert.h"
+#include "QtTest/qtestdata.h"
+#include "QtTest/private/qtesttable_p.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTestDataPrivate
+{
+public:
+ QTestDataPrivate(): tag(0), parent(0), data(0), dataCount(0) {}
+
+ char *tag;
+ QTestTable *parent;
+ void **data;
+ int dataCount;
+};
+
+QTestData::QTestData(const char *tag, QTestTable *parent)
+{
+ QTEST_ASSERT(tag);
+ QTEST_ASSERT(parent);
+ d = new QTestDataPrivate;
+ d->tag = qstrdup(tag);
+ d->parent = parent;
+ d->data = new void *[parent->elementCount()];
+ memset(d->data, 0, parent->elementCount() * sizeof(void*));
+}
+
+QTestData::~QTestData()
+{
+ for (int i = 0; i < d->dataCount; ++i) {
+ if (d->data[i])
+ QMetaType::destroy(d->parent->elementTypeId(i), d->data[i]);
+ }
+ delete [] d->data;
+ delete [] d->tag;
+ delete d;
+}
+
+void QTestData::append(int type, const void *data)
+{
+ QTEST_ASSERT(d->dataCount < d->parent->elementCount());
+ if (d->parent->elementTypeId(d->dataCount) != type) {
+ qDebug("expected data of type '%s', got '%s' for element %d of data with tag '%s'",
+ QMetaType::typeName(d->parent->elementTypeId(d->dataCount)),
+ QMetaType::typeName(type),
+ d->dataCount, d->tag);
+ QTEST_ASSERT(false);
+ }
+ d->data[d->dataCount] = QMetaType::construct(type, data);
+ ++d->dataCount;
+}
+
+void *QTestData::data(int index) const
+{
+ QTEST_ASSERT(index >= 0);
+ QTEST_ASSERT(index < d->parent->elementCount());
+ return d->data[index];
+}
+
+QTestTable *QTestData::parent() const
+{
+ return d->parent;
+}
+
+const char *QTestData::dataTag() const
+{
+ return d->tag;
+}
+
+int QTestData::dataCount() const
+{
+ return d->dataCount;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtestdata.h b/src/testlib/qtestdata.h
new file mode 100644
index 0000000000..b39bce2d0e
--- /dev/null
+++ b/src/testlib/qtestdata.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTDATA_H
+#define QTESTDATA_H
+
+#include <QtTest/qtest_global.h>
+
+#include <QtCore/qmetatype.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QTestTable;
+class QTestDataPrivate;
+
+class Q_TESTLIB_EXPORT QTestData
+{
+public:
+ ~QTestData();
+
+ void append(int type, const void *data);
+ void *data(int index) const;
+ const char *dataTag() const;
+ QTestTable *parent() const;
+ int dataCount() const;
+
+private:
+ friend class QTestTable;
+ QTestData(const char *tag = 0, QTestTable *parent = 0);
+
+ Q_DISABLE_COPY(QTestData)
+
+ QTestDataPrivate *d;
+};
+
+template<typename T>
+QTestData &operator<<(QTestData &data, const T &value)
+{
+ data.append(qMetaTypeId<T>(), &value);
+ return data;
+}
+
+inline QTestData &operator<<(QTestData &data, const char * value)
+{
+ QString str = QString::fromAscii(value);
+ data.append(QMetaType::QString, &str);
+ return data;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestelement.cpp b/src/testlib/qtestelement.cpp
new file mode 100644
index 0000000000..93f85b313d
--- /dev/null
+++ b/src/testlib/qtestelement.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtestelement.h"
+
+QT_BEGIN_NAMESPACE
+
+QTestElement::QTestElement(int type)
+ :QTestCoreElement<QTestElement>(type),
+ listOfChildren(0),
+ parent(0)
+{
+}
+
+QTestElement::~QTestElement()
+{
+ delete listOfChildren;
+}
+
+bool QTestElement::addLogElement(QTestElement *element)
+{
+ if(!element)
+ return false;
+
+ if(element->elementType() != QTest::LET_Undefined){
+ element->addToList(&listOfChildren);
+ element->setParent(this);
+ return true;
+ }
+
+ return false;
+}
+
+QTestElement *QTestElement::childElements() const
+{
+ return listOfChildren;
+}
+
+const QTestElement *QTestElement::parentElement() const
+{
+ return parent;
+}
+
+void QTestElement::setParent(const QTestElement *p)
+{
+ parent = p;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/testlib/qtestelement.h b/src/testlib/qtestelement.h
new file mode 100644
index 0000000000..ec1d0a346b
--- /dev/null
+++ b/src/testlib/qtestelement.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTELEMENT_H
+#define QTESTELEMENT_H
+
+#include <QtTest/qtestcoreelement.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QTestElement: public QTestCoreElement<QTestElement>
+{
+ public:
+ QTestElement(int type = -1);
+ ~QTestElement();
+
+ bool addLogElement(QTestElement *element);
+ QTestElement *childElements() const;
+
+ const QTestElement *parentElement() const;
+ void setParent(const QTestElement *p);
+
+ private:
+ QTestElement *listOfChildren;
+ const QTestElement * parent;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestelementattribute.cpp b/src/testlib/qtestelementattribute.cpp
new file mode 100644
index 0000000000..aec3376564
--- /dev/null
+++ b/src/testlib/qtestelementattribute.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtestelementattribute.h"
+#include <QtCore/qbytearray.h>
+#include <string.h>
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+/*! \enum QTest::AttributeIndex
+ This enum numbers the different tests.
+
+ \value AI_Undefined
+
+ \value AI_Name
+
+ \value AI_Result
+
+ \value AI_Tests
+
+ \value AI_Failures
+
+ \value AI_Errors
+
+ \value AI_Type
+
+ \value AI_Description
+
+ \value AI_PropertyValue
+
+ \value AI_QTestVersion
+
+ \value AI_QtVersion
+
+ \value AI_File
+
+ \value AI_Line
+
+ \value AI_Metric
+
+ \value AI_Tag
+
+ \value AI_Value
+
+ \value AI_Iterations
+*/
+
+/*! \enum QTest::LogElementType
+ The enum specifies the kinds of test log messages.
+
+ \value LET_Undefined
+
+ \value LET_Property
+
+ \value LET_Properties
+
+ \value LET_Failure
+
+ \value LET_Error
+
+ \value LET_TestCase
+
+ \value LET_TestSuite
+
+ \value LET_Benchmark
+
+ \value LET_SystemError
+*/
+
+QTestElementAttribute::QTestElementAttribute()
+ :attributeValue(0),
+ attributeIndex(QTest::AI_Undefined)
+{
+}
+
+QTestElementAttribute::~QTestElementAttribute()
+{
+ delete[] attributeValue;
+}
+
+const char *QTestElementAttribute::value() const
+{
+ return attributeValue;
+}
+
+const char *QTestElementAttribute::name() const
+{
+ const char *AttributeNames[] =
+ {
+ "name",
+ "result",
+ "tests",
+ "failures",
+ "errors",
+ "type",
+ "description",
+ "value",
+ "qtestversion",
+ "qtversion",
+ "file",
+ "line",
+ "metric",
+ "tag",
+ "value",
+ "iterations"
+ };
+
+ if(attributeIndex != QTest::AI_Undefined)
+ return AttributeNames[attributeIndex];
+
+ return 0;
+}
+
+QTest::AttributeIndex QTestElementAttribute::index() const
+{
+ return attributeIndex;
+}
+
+bool QTestElementAttribute::isNull() const
+{
+ return attributeIndex == QTest::AI_Undefined;
+}
+
+bool QTestElementAttribute::setPair(QTest::AttributeIndex index, const char *value)
+{
+ if(!value)
+ return false;
+
+ delete[] attributeValue;
+
+ attributeIndex = index;
+ attributeValue = qstrdup(value);
+
+ return (attributeValue!=0) ? true:false;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/testlib/qtestelementattribute.h b/src/testlib/qtestelementattribute.h
new file mode 100644
index 0000000000..6b55c8a0d3
--- /dev/null
+++ b/src/testlib/qtestelementattribute.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTELEMENTATTRIBUTE_H
+#define QTESTELEMENTATTRIBUTE_H
+
+#include <QtTest/qtestcorelist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest {
+
+ enum AttributeIndex
+ {
+ AI_Undefined = -1,
+ AI_Name = 0,
+ AI_Result = 1,
+ AI_Tests = 2,
+ AI_Failures = 3,
+ AI_Errors = 4,
+ AI_Type = 5,
+ AI_Description = 6,
+ AI_PropertyValue = 7,
+ AI_QTestVersion = 8,
+ AI_QtVersion = 9,
+ AI_File = 10,
+ AI_Line = 11,
+ AI_Metric = 12,
+ AI_Tag = 13,
+ AI_Value = 14,
+ AI_Iterations = 15
+ };
+
+ enum LogElementType
+ {
+ LET_Undefined = -1,
+ LET_Property = 0,
+ LET_Properties = 1,
+ LET_Failure = 2,
+ LET_Error = 3,
+ LET_TestCase = 4,
+ LET_TestSuite = 5,
+ LET_Benchmark = 6,
+ LET_SystemError = 7
+ };
+}
+
+class QTestElementAttribute: public QTestCoreList<QTestElementAttribute>
+{
+ public:
+ QTestElementAttribute();
+ ~QTestElementAttribute();
+
+ const char *value() const;
+ const char *name() const;
+ QTest::AttributeIndex index() const;
+ bool isNull() const;
+ bool setPair(QTest::AttributeIndex attributeIndex, const char *value);
+
+ private:
+ char *attributeValue;
+ QTest::AttributeIndex attributeIndex;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestevent.h b/src/testlib/qtestevent.h
new file mode 100644
index 0000000000..f1f42c7438
--- /dev/null
+++ b/src/testlib/qtestevent.h
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTEVENT_H
+#define QTESTEVENT_H
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+#include <QtTest/qtest_global.h>
+#ifdef QT_GUI_LIB
+#include <QtTest/qtestkeyboard.h>
+#include <QtTest/qtestmouse.h>
+#endif
+#include <QtTest/qtestsystem.h>
+
+#include <QtCore/qlist.h>
+
+#include <stdlib.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QTestEvent
+{
+public:
+ virtual void simulate(QWidget *w) = 0;
+ virtual QTestEvent *clone() const = 0;
+
+ virtual ~QTestEvent() {}
+};
+
+#ifdef QT_GUI_LIB
+class QTestKeyEvent: public QTestEvent
+{
+public:
+ inline QTestKeyEvent(QTest::KeyAction action, Qt::Key key, Qt::KeyboardModifiers modifiers, int delay)
+ : _action(action), _delay(delay), _modifiers(modifiers), _ascii(0), _key(key) {}
+ inline QTestKeyEvent(QTest::KeyAction action, char ascii, Qt::KeyboardModifiers modifiers, int delay)
+ : _action(action), _delay(delay), _modifiers(modifiers),
+ _ascii(ascii), _key(Qt::Key_unknown) {}
+ inline QTestEvent *clone() const { return new QTestKeyEvent(*this); }
+
+ inline void simulate(QWidget *w)
+ {
+ if (_ascii == 0)
+ QTest::keyEvent(_action, w, _key, _modifiers, _delay);
+ else
+ QTest::keyEvent(_action, w, _ascii, _modifiers, _delay);
+ }
+
+protected:
+ QTest::KeyAction _action;
+ int _delay;
+ Qt::KeyboardModifiers _modifiers;
+ char _ascii;
+ Qt::Key _key;
+};
+
+class QTestKeyClicksEvent: public QTestEvent
+{
+public:
+ inline QTestKeyClicksEvent(const QString &keys, Qt::KeyboardModifiers modifiers, int delay)
+ : _keys(keys), _modifiers(modifiers), _delay(delay) {}
+ inline QTestEvent *clone() const { return new QTestKeyClicksEvent(*this); }
+
+ inline void simulate(QWidget *w)
+ {
+ QTest::keyClicks(w, _keys, _modifiers, _delay);
+ }
+
+private:
+ QString _keys;
+ Qt::KeyboardModifiers _modifiers;
+ int _delay;
+};
+
+class QTestMouseEvent: public QTestEvent
+{
+public:
+ inline QTestMouseEvent(QTest::MouseAction action, Qt::MouseButton button,
+ Qt::KeyboardModifiers modifiers, QPoint position, int delay)
+ : _action(action), _button(button), _modifiers(modifiers), _pos(position), _delay(delay) {}
+ inline QTestEvent *clone() const { return new QTestMouseEvent(*this); }
+
+ inline void simulate(QWidget *w)
+ {
+ QTest::mouseEvent(_action, w, _button, _modifiers, _pos, _delay);
+ }
+
+private:
+ QTest::MouseAction _action;
+ Qt::MouseButton _button;
+ Qt::KeyboardModifiers _modifiers;
+ QPoint _pos;
+ int _delay;
+};
+#endif //QT_GUI_LIB
+
+
+class QTestDelayEvent: public QTestEvent
+{
+public:
+ inline QTestDelayEvent(int msecs): _delay(msecs) {}
+ inline QTestEvent *clone() const { return new QTestDelayEvent(*this); }
+
+ inline void simulate(QWidget * /*w*/) { QTest::qWait(_delay); }
+
+private:
+ int _delay;
+};
+
+class QTestEventList: public QList<QTestEvent *>
+{
+public:
+ inline QTestEventList() {}
+ inline QTestEventList(const QTestEventList &other): QList<QTestEvent *>()
+ { for (int i = 0; i < other.count(); ++i) append(other.at(i)->clone()); }
+ inline ~QTestEventList()
+ { clear(); }
+ inline void clear()
+ { qDeleteAll(*this); QList<QTestEvent *>::clear(); }
+
+#ifdef QT_GUI_LIB
+ inline void addKeyClick(Qt::Key qtKey, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { addKeyEvent(QTest::Click, qtKey, modifiers, msecs); }
+ inline void addKeyPress(Qt::Key qtKey, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { addKeyEvent(QTest::Press, qtKey, modifiers, msecs); }
+ inline void addKeyRelease(Qt::Key qtKey, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { addKeyEvent(QTest::Release, qtKey, modifiers, msecs); }
+ inline void addKeyEvent(QTest::KeyAction action, Qt::Key qtKey,
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { append(new QTestKeyEvent(action, qtKey, modifiers, msecs)); }
+
+ inline void addKeyClick(char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { addKeyEvent(QTest::Click, ascii, modifiers, msecs); }
+ inline void addKeyPress(char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { addKeyEvent(QTest::Press, ascii, modifiers, msecs); }
+ inline void addKeyRelease(char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { addKeyEvent(QTest::Release, ascii, modifiers, msecs); }
+ inline void addKeyClicks(const QString &keys, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { append(new QTestKeyClicksEvent(keys, modifiers, msecs)); }
+ inline void addKeyEvent(QTest::KeyAction action, char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ { append(new QTestKeyEvent(action, ascii, modifiers, msecs)); }
+
+ inline void addMousePress(Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { append(new QTestMouseEvent(QTest::MousePress, button, stateKey, pos, delay)); }
+ inline void addMouseRelease(Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { append(new QTestMouseEvent(QTest::MouseRelease, button, stateKey, pos, delay)); }
+ inline void addMouseClick(Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { append(new QTestMouseEvent(QTest::MouseClick, button, stateKey, pos, delay)); }
+ inline void addMouseDClick(Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { append(new QTestMouseEvent(QTest::MouseDClick, button, stateKey, pos, delay)); }
+ inline void addMouseMove(QPoint pos = QPoint(), int delay=-1)
+ { append(new QTestMouseEvent(QTest::MouseMove, Qt::NoButton, 0, pos, delay)); }
+#endif //QT_GUI_LIB
+
+ inline void addDelay(int msecs)
+ { append(new QTestDelayEvent(msecs)); }
+
+ inline void simulate(QWidget *w)
+ {
+ for (int i = 0; i < count(); ++i)
+ at(i)->simulate(w);
+ }
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QTestEventList)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestevent.qdoc b/src/testlib/qtestevent.qdoc
new file mode 100644
index 0000000000..4c695c2885
--- /dev/null
+++ b/src/testlib/qtestevent.qdoc
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QTestEventList
+ \inmodule QtTest
+
+ \brief The QTestEventList class provides a list of GUI events.
+
+ QTestEventList inherits from QList<QTestEvent *>, and provides
+ convenience functions for populating the list.
+
+ A QTestEventList can be populated with GUI events that can be
+ stored as test data for later usage, or be replayed on any
+ QWidget.
+
+ Example:
+ \snippet doc/src/snippets/code/doc_src_qtestevent.cpp 0
+
+ The example above simulates the user entering the character \c a
+ followed by a backspace, waiting for 200 milliseconds and
+ repeating it.
+*/
+
+/*! \fn QTestEventList::QTestEventList()
+
+ Constructs an empty QTestEventList.
+*/
+
+/*! \fn QTestEventList::QTestEventList(const QTestEventList &other)
+
+ Constructs a new QTestEventList as a copy of \a other.
+*/
+
+/*! \fn QTestEventList::~QTestEventList()
+
+ Empties the list and destroys all stored events.
+*/
+
+/*! \fn void QTestEventList::clear()
+
+ Removes all events from the list.
+*/
+
+/*! \fn void QTestEventList::addKeyClick(Qt::Key qtKey, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+
+ Adds a new key click to the list. The event will simulate the key \a qtKey with the modifier \a modifiers and then wait for \a msecs milliseconds.
+
+ \sa QTest::keyClick()
+*/
+
+/*! \fn void QTestEventList::addKeyPress(Qt::Key qtKey, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+
+ Adds a new key press to the list. The event will press the key \a qtKey with the modifier \a modifiers and then wait for \a msecs milliseconds.
+
+ \sa QTest::keyPress()
+*/
+
+/*! \fn void QTestEventList::addKeyRelease(Qt::Key qtKey, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+
+ Adds a new key release to the list. The event will release the key \a qtKey with the modifier \a modifiers and then wait for \a msecs milliseconds.
+
+ \sa QTest::keyRelease()
+
+*/
+
+/*! \fn void QTestEventList::addKeyEvent(QTest::KeyAction action, Qt::Key qtKey, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ \internal
+*/
+
+/*! \fn void QTestEventList::addKeyClick(char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+
+ \overload
+
+ Adds a new key click to the list. The event will simulate the key \a ascii with the modifier \a modifiers and then wait for \a msecs milliseconds.
+
+ \sa QTest::keyClick()
+
+*/
+
+/*! \fn void QTestEventList::addKeyPress(char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+
+ \overload
+
+ Adds a new key press to the list. The event will press the key \a ascii with the modifier \a modifiers and then wait for \a msecs milliseconds.
+
+ \sa QTest::keyPress()
+*/
+
+/*! \fn void QTestEventList::addKeyRelease(char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+
+ \overload
+
+ Adds a new key release to the list. The event will release the key \a ascii with the modifier \a modifiers and then wait for \a msecs milliseconds.
+
+ \sa QTest::keyRelease()
+*/
+
+/*! \fn void QTestEventList::addKeyClicks(const QString &keys, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+
+ Adds new keyboard entries to the list. The event will press the \a keys with the \a modifiers and wait \a msecs milliseconds between each key.
+
+ \sa QTest::keyClicks()
+*/
+
+/*! \fn void QTestEventList::addKeyEvent(QTest::KeyAction action, char ascii, Qt::KeyboardModifiers modifiers = Qt::NoModifier, int msecs = -1)
+ \internal
+*/
+
+/*! \fn void QTestEventList::addDelay(int msecs)
+
+ Adds a \a msecs milliseconds delay.
+
+ \sa QTest::qWait()
+*/
+
+/*! \fn void QTestEventList::simulate(QWidget *w)
+
+ Simulates the events from the list one by one on the widget \a w.
+ For an example, please read the \l QTestEventList class documentation.
+*/
+
+/*! \fn void QTestEventList::addMousePress(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Add a mouse press to the list. The event will press the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
+
+ \sa QTest::mousePress()
+*/
+/*! \fn void QTestEventList::addMouseRelease(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Add a mouse release to the list. The event will release the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
+
+ \sa QTest::mouseRelease()
+*/
+/*! \fn void QTestEventList::addMouseClick(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Add a mouse click to the list. The event will click the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
+
+ \sa QTest::mouseClick()
+*/
+/*! \fn void QTestEventList::addMouseDClick(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+
+ Add a double mouse click to the list. The event will double click the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
+
+ \sa QTest::mousePress()
+*/
+/*! \fn void QTestEventList::addMouseMove(QPoint pos = QPoint(), int delay=-1)
+
+ Adds a mouse move to the list. The event will move the mouse to the position \a pos. If a \a delay (in milliseconds) is set, the test will wait after moving the mouse. The default position is the center of the widget.
+
+ \sa QTest::mousePress()
+*/
+
diff --git a/src/testlib/qtesteventloop.h b/src/testlib/qtesteventloop.h
new file mode 100644
index 0000000000..6471dbb07d
--- /dev/null
+++ b/src/testlib/qtesteventloop.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTEVENTLOOP_H
+#define QTESTEVENTLOOP_H
+
+#include <QtTest/qtest_global.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qeventloop.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class Q_TESTLIB_EXPORT QTestEventLoop : public QObject
+{
+ Q_OBJECT
+
+public:
+ inline QTestEventLoop(QObject *aParent = 0)
+ : QObject(aParent), inLoop(false), _timeout(false), timerId(-1), loop(0) {}
+ inline void enterLoop(int secs);
+
+
+ inline void changeInterval(int secs)
+ { killTimer(timerId); timerId = startTimer(secs * 1000); }
+
+ inline bool timeout() const
+ { return _timeout; }
+
+ inline static QTestEventLoop &instance()
+ {
+ static QPointer<QTestEventLoop> testLoop;
+ if (testLoop.isNull())
+ testLoop = new QTestEventLoop(QCoreApplication::instance());
+ return *static_cast<QTestEventLoop *>(testLoop);
+ }
+
+public Q_SLOTS:
+ inline void exitLoop();
+
+protected:
+ inline void timerEvent(QTimerEvent *e);
+
+private:
+ bool inLoop;
+ bool _timeout;
+ int timerId;
+
+ QEventLoop *loop;
+};
+
+inline void QTestEventLoop::enterLoop(int secs)
+{
+ Q_ASSERT(!loop);
+
+ QEventLoop l;
+
+ inLoop = true;
+ _timeout = false;
+
+ timerId = startTimer(secs * 1000);
+
+ loop = &l;
+ l.exec();
+ loop = 0;
+}
+
+inline void QTestEventLoop::exitLoop()
+{
+ if (timerId != -1)
+ killTimer(timerId);
+ timerId = -1;
+
+ if (loop)
+ loop->exit();
+
+ inLoop = false;
+}
+
+inline void QTestEventLoop::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() != timerId)
+ return;
+ _timeout = true;
+ exitLoop();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestfilelogger.cpp b/src/testlib/qtestfilelogger.cpp
new file mode 100644
index 0000000000..a8864664af
--- /dev/null
+++ b/src/testlib/qtestfilelogger.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtestfilelogger.h"
+#include "qtestassert.h"
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/private/qtestresult_p.h"
+
+#include <QtCore/qdir.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest
+{
+ static FILE *stream = 0;
+}
+
+QTestFileLogger::QTestFileLogger()
+{
+}
+
+QTestFileLogger::~QTestFileLogger()
+{
+ if(QTest::stream)
+ fclose(QTest::stream);
+
+ QTest::stream = 0;
+}
+
+void QTestFileLogger::init()
+{
+ char filename[100];
+ int index = 0;
+#if defined(Q_OS_SYMBIAN)
+ QByteArray ba(QDir::toNativeSeparators(QString(QDir::homePath()+QDir::separator())).toUtf8());
+ index = ba.length();
+ QTest::qt_snprintf(filename, sizeof(filename), "%s%s.log",
+ ba.constData(), QTestResult::currentTestObjectName());
+#else
+ QTest::qt_snprintf(filename, sizeof(filename), "%s.log",
+ QTestResult::currentTestObjectName());
+#endif
+
+ // Keep filenames simple
+ for (uint i = index; i < sizeof(filename) && filename[i]; ++i) {
+ char& c = filename[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
+ c = '_';
+ }
+ }
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE)
+ if (::fopen_s(&QTest::stream, filename, "wt")) {
+#else
+ QTest::stream = ::fopen(filename, "wt");
+ if (!QTest::stream) {
+#endif
+ printf("Unable to open file for simple logging: %s", filename);
+ ::exit(1);
+ }
+}
+
+void QTestFileLogger::flush(const char *msg)
+{
+ QTEST_ASSERT(QTest::stream);
+
+ ::fputs(msg, QTest::stream);
+ ::fflush(QTest::stream);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/testlib/qtestfilelogger.h b/src/testlib/qtestfilelogger.h
new file mode 100644
index 0000000000..08c306547e
--- /dev/null
+++ b/src/testlib/qtestfilelogger.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTFILELOGGER_H
+#define QTESTFILELOGGER_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QTestFileLogger
+{
+ public:
+ QTestFileLogger();
+ ~QTestFileLogger();
+
+ void init();
+ void flush(const char *msg);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTESTFILELOGGER_H
diff --git a/src/testlib/qtestkeyboard.h b/src/testlib/qtestkeyboard.h
new file mode 100644
index 0000000000..37be098512
--- /dev/null
+++ b/src/testlib/qtestkeyboard.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if !defined(QTESTKEYBOARD_H)
+#define QTESTKEYBOARD_H
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+#include <QtTest/qtestassert.h>
+#include <QtTest/qtest_global.h>
+#include <QtTest/qtestsystem.h>
+#include <QtTest/qtestspontaneevent.h>
+
+#include <QtCore/qpointer.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest
+{
+ enum KeyAction { Press, Release, Click };
+
+ static void simulateEvent(QWidget *widget, bool press, int code,
+ Qt::KeyboardModifiers modifier, QString text, bool repeat, int delay=-1)
+ {
+ QTEST_ASSERT(widget);
+ extern int Q_TESTLIB_EXPORT defaultKeyDelay();
+
+ if (delay == -1 || delay < defaultKeyDelay())
+ delay = defaultKeyDelay();
+ if(delay > 0)
+ QTest::qWait(delay);
+
+ QKeyEvent a(press ? QEvent::KeyPress : QEvent::KeyRelease, code, modifier, text, repeat);
+ QSpontaneKeyEvent::setSpontaneous(&a);
+ if (!qApp->notify(widget, &a))
+ QTest::qWarn("Keyboard event not accepted by receiving widget");
+ }
+
+ static void sendKeyEvent(KeyAction action, QWidget *widget, Qt::Key code,
+ QString text, Qt::KeyboardModifiers modifier, int delay=-1)
+ {
+ QTEST_ASSERT(qApp);
+
+ if (!widget)
+ widget = QWidget::keyboardGrabber();
+ if (!widget) {
+ if (QWidget *apw = QApplication::activePopupWidget())
+ widget = apw->focusWidget() ? apw->focusWidget() : apw;
+ else
+ widget = QApplication::focusWidget();
+ }
+ if (!widget)
+ widget = QApplication::activeWindow();
+
+ QTEST_ASSERT(widget);
+
+ if (action == Click) {
+ QPointer<QWidget> ptr(widget);
+ sendKeyEvent(Press, widget, code, text, modifier, delay);
+ if (!ptr) {
+ // if we send key-events to embedded widgets, they might be destroyed
+ // when the user presses Return
+ return;
+ }
+ sendKeyEvent(Release, widget, code, text, modifier, delay);
+ return;
+ }
+
+ bool repeat = false;
+
+ if (action == Press) {
+ if (modifier & Qt::ShiftModifier)
+ simulateEvent(widget, true, Qt::Key_Shift, 0, QString(), false, delay);
+
+ if (modifier & Qt::ControlModifier)
+ simulateEvent(widget, true, Qt::Key_Control, modifier & Qt::ShiftModifier, QString(), false, delay);
+
+ if (modifier & Qt::AltModifier)
+ simulateEvent(widget, true, Qt::Key_Alt,
+ modifier & (Qt::ShiftModifier | Qt::ControlModifier), QString(), false, delay);
+ if (modifier & Qt::MetaModifier)
+ simulateEvent(widget, true, Qt::Key_Meta, modifier & (Qt::ShiftModifier
+ | Qt::ControlModifier | Qt::AltModifier), QString(), false, delay);
+ simulateEvent(widget, true, code, modifier, text, repeat, delay);
+ } else if (action == Release) {
+ simulateEvent(widget, false, code, modifier, text, repeat, delay);
+
+ if (modifier & Qt::MetaModifier)
+ simulateEvent(widget, false, Qt::Key_Meta, modifier, QString(), false, delay);
+ if (modifier & Qt::AltModifier)
+ simulateEvent(widget, false, Qt::Key_Alt, modifier &
+ (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier), QString(), false, delay);
+
+ if (modifier & Qt::ControlModifier)
+ simulateEvent(widget, false, Qt::Key_Control,
+ modifier & (Qt::ShiftModifier | Qt::ControlModifier), QString(), false, delay);
+
+ if (modifier & Qt::ShiftModifier)
+ simulateEvent(widget, false, Qt::Key_Shift, modifier & Qt::ShiftModifier, QString(), false, delay);
+ }
+ }
+
+ // Convenience function
+ static void sendKeyEvent(KeyAction action, QWidget *widget, Qt::Key code,
+ char ascii, Qt::KeyboardModifiers modifier, int delay=-1)
+ {
+ QString text;
+ if (ascii)
+ text = QString(QChar::fromLatin1(ascii));
+ sendKeyEvent(action, widget, code, text, modifier, delay);
+ }
+
+ inline static void keyEvent(KeyAction action, QWidget *widget, char ascii,
+ Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { sendKeyEvent(action, widget, asciiToKey(ascii), ascii, modifier, delay); }
+ inline static void keyEvent(KeyAction action, QWidget *widget, Qt::Key key,
+ Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { sendKeyEvent(action, widget, key, keyToAscii(key), modifier, delay); }
+
+ inline static void keyClicks(QWidget *widget, const QString &sequence,
+ Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ {
+ for (int i=0; i < sequence.length(); i++)
+ keyEvent(Click, widget, sequence.at(i).toLatin1(), modifier, delay);
+ }
+
+ inline static void keyPress(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { keyEvent(Press, widget, key, modifier, delay); }
+ inline static void keyRelease(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { keyEvent(Release, widget, key, modifier, delay); }
+ inline static void keyClick(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { keyEvent(Click, widget, key, modifier, delay); }
+ inline static void keyPress(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { keyEvent(Press, widget, key, modifier, delay); }
+ inline static void keyRelease(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { keyEvent(Release, widget, key, modifier, delay); }
+ inline static void keyClick(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1)
+ { keyEvent(Click, widget, key, modifier, delay); }
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTESTKEYBOARD_H
diff --git a/src/testlib/qtestlightxmlstreamer.cpp b/src/testlib/qtestlightxmlstreamer.cpp
new file mode 100644
index 0000000000..7bdd34c09c
--- /dev/null
+++ b/src/testlib/qtestlightxmlstreamer.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtestlightxmlstreamer.h"
+#include "qtestelement.h"
+#include "qtestelementattribute.h"
+#include "qtestlogger_p.h"
+
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/private/qtestresult_p.h"
+#include "QtTest/private/qxmltestlogger_p.h"
+
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+QTestLightXmlStreamer::QTestLightXmlStreamer()
+ :QTestBasicStreamer()
+{
+}
+
+QTestLightXmlStreamer::~QTestLightXmlStreamer()
+{}
+
+void QTestLightXmlStreamer::formatStart(const QTestElement *element, QTestCharBuffer *formatted) const
+{
+ if(!element || !formatted)
+ return;
+
+ switch(element->elementType()){
+ case QTest::LET_TestCase: {
+ QTestCharBuffer quotedTf;
+ QXmlTestLogger::xmlQuote(&quotedTf, element->attributeValue(QTest::AI_Name));
+
+ QTest::qt_asprintf(formatted, "<TestFunction name=\"%s\">\n", quotedTf.constData());
+ break;
+ }
+ case QTest::LET_Failure: {
+ QTestCharBuffer cdataDesc;
+ QXmlTestLogger::xmlCdata(&cdataDesc, element->attributeValue(QTest::AI_Description));
+
+ QTest::qt_asprintf(formatted, " <Description><![CDATA[%s]]></Description>\n",
+ cdataDesc.constData());
+ break;
+ }
+ case QTest::LET_Error: {
+ // assuming type and attribute names don't need quoting
+ QTestCharBuffer quotedFile;
+ QTestCharBuffer cdataDesc;
+ QXmlTestLogger::xmlQuote(&quotedFile, element->attributeValue(QTest::AI_File));
+ QXmlTestLogger::xmlCdata(&cdataDesc, element->attributeValue(QTest::AI_Description));
+
+ QTest::qt_asprintf(formatted, "<Message type=\"%s\" %s=\"%s\" %s=\"%s\">\n <Description><![CDATA[%s]]></Description>\n</Message>\n",
+ element->attributeValue(QTest::AI_Type),
+ element->attributeName(QTest::AI_File),
+ quotedFile.constData(),
+ element->attributeName(QTest::AI_Line),
+ element->attributeValue(QTest::AI_Line),
+ cdataDesc.constData());
+ break;
+ }
+ case QTest::LET_Benchmark: {
+ // assuming value and iterations don't need quoting
+ QTestCharBuffer quotedMetric;
+ QTestCharBuffer quotedTag;
+ QXmlTestLogger::xmlQuote(&quotedMetric, element->attributeValue(QTest::AI_Metric));
+ QXmlTestLogger::xmlQuote(&quotedTag, element->attributeValue(QTest::AI_Tag));
+
+ QTest::qt_asprintf(formatted, "<BenchmarkResult %s=\"%s\" %s=\"%s\" %s=\"%s\" %s=\"%s\" />\n",
+ element->attributeName(QTest::AI_Metric),
+ quotedMetric.constData(),
+ element->attributeName(QTest::AI_Tag),
+ quotedTag.constData(),
+ element->attributeName(QTest::AI_Value),
+ element->attributeValue(QTest::AI_Value),
+ element->attributeName(QTest::AI_Iterations),
+ element->attributeValue(QTest::AI_Iterations) );
+ break;
+ }
+ default:
+ formatted->data()[0] = '\0';
+ }
+}
+
+void QTestLightXmlStreamer::formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const
+{
+ if(!element || !formatted)
+ return;
+
+ if (element->elementType() == QTest::LET_TestCase) {
+ if( element->attribute(QTest::AI_Result) && element->childElements())
+ QTest::qt_asprintf(formatted, "</Incident>\n</TestFunction>\n");
+ else
+ QTest::qt_asprintf(formatted, "</TestFunction>\n");
+ } else {
+ formatted->data()[0] = '\0';
+ }
+}
+
+void QTestLightXmlStreamer::formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const
+{
+ if(!element || !formatted)
+ return;
+
+ if (element->elementType() == QTest::LET_TestCase && element->attribute(QTest::AI_Result)) {
+ QTestCharBuffer buf;
+ QTestCharBuffer quotedFile;
+ QXmlTestLogger::xmlQuote(&quotedFile, element->attributeValue(QTest::AI_File));
+
+ QTest::qt_asprintf(&buf, "%s=\"%s\" %s=\"%s\"",
+ element->attributeName(QTest::AI_File),
+ quotedFile.constData(),
+ element->attributeName(QTest::AI_Line),
+ element->attributeValue(QTest::AI_Line));
+
+ if( !element->childElements() )
+ QTest::qt_asprintf(formatted, "<Incident type=\"%s\" %s/>\n",
+ element->attributeValue(QTest::AI_Result), buf.constData());
+ else
+ QTest::qt_asprintf(formatted, "<Incident type=\"%s\" %s>\n",
+ element->attributeValue(QTest::AI_Result), buf.constData());
+ } else {
+ formatted->data()[0] = '\0';
+ }
+}
+
+void QTestLightXmlStreamer::output(QTestElement *element) const
+{
+ QTestCharBuffer buf;
+ if (logger()->hasRandomSeed()) {
+ QTest::qt_asprintf(&buf, "<Environment>\n <QtVersion>%s</QtVersion>\n <QTestVersion>%s</QTestVersion>\n <RandomSeed>%d</RandomSeed>\n",
+ qVersion(), QTEST_VERSION_STR, logger()->randomSeed() );
+ } else {
+ QTest::qt_asprintf(&buf, "<Environment>\n <QtVersion>%s</QtVersion>\n <QTestVersion>%s</QTestVersion>\n",
+ qVersion(), QTEST_VERSION_STR );
+ }
+ outputString(buf.constData());
+
+ QTest::qt_asprintf(&buf, "</Environment>\n");
+ outputString(buf.constData());
+
+ QTestBasicStreamer::output(element);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/testlib/qtestlightxmlstreamer.h b/src/testlib/qtestlightxmlstreamer.h
new file mode 100644
index 0000000000..265a31b29d
--- /dev/null
+++ b/src/testlib/qtestlightxmlstreamer.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTLIGHTXMLSTREAMER_H
+#define QTESTLIGHTXMLSTREAMER_H
+
+#include <QtTest/qtestbasicstreamer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QTestElement;
+class QTestElementAttribute;
+
+class QTestLightXmlStreamer: public QTestBasicStreamer
+{
+ public:
+ QTestLightXmlStreamer();
+ ~QTestLightXmlStreamer();
+
+ void formatStart(const QTestElement *element, QTestCharBuffer *formatted) const;
+ void formatEnd(const QTestElement *element, QTestCharBuffer *formatted) const;
+ void formatBeforeAttributes(const QTestElement *element, QTestCharBuffer *formatted) const;
+ void output(QTestElement *element) const;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp
new file mode 100644
index 0000000000..ed9a005736
--- /dev/null
+++ b/src/testlib/qtestlog.cpp
@@ -0,0 +1,393 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/qtestassert.h"
+
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/private/qtestresult_p.h"
+#include "QtTest/private/qabstracttestlogger_p.h"
+#include "QtTest/private/qplaintestlogger_p.h"
+#include "QtTest/private/qxmltestlogger_p.h"
+#include <QtCore/qatomic.h>
+#include <QtCore/qbytearray.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+
+#include "qtestlogger_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest {
+
+ struct IgnoreResultList
+ {
+ inline IgnoreResultList(QtMsgType tp, const char *message)
+ : type(tp), next(0)
+ { msg = qstrdup(message); }
+ inline ~IgnoreResultList()
+ { delete [] msg; }
+
+ static inline void clearList(IgnoreResultList *&list)
+ {
+ while (list) {
+ IgnoreResultList *current = list;
+ list = list->next;
+ delete current;
+ }
+ }
+
+ QtMsgType type;
+ char *msg;
+ IgnoreResultList *next;
+ };
+
+ static IgnoreResultList *ignoreResultList = 0;
+
+ static QTestLog::LogMode logMode = QTestLog::Plain;
+ static QTestLog::FlushMode flushMode = QTestLog::NoFlush;
+ static int verbosity = 0;
+ static int maxWarnings = 2002;
+
+ static QAbstractTestLogger *testLogger = 0;
+ static const char *outFile = 0;
+
+ static QtMsgHandler oldMessageHandler;
+
+ static bool handleIgnoredMessage(QtMsgType type, const char *msg)
+ {
+ IgnoreResultList *last = 0;
+ IgnoreResultList *list = ignoreResultList;
+ while (list) {
+ if (list->type == type && strcmp(msg, list->msg) == 0) {
+ // remove the item from the list
+ if (last)
+ last->next = list->next;
+ else if (list->next)
+ ignoreResultList = list->next;
+ else
+ ignoreResultList = 0;
+
+ delete list;
+ return true;
+ }
+
+ last = list;
+ list = list->next;
+ }
+ return false;
+ }
+
+ static void messageHandler(QtMsgType type, const char *msg)
+ {
+ static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(QTest::maxWarnings);
+
+ if (!msg || !QTest::testLogger) {
+ // if this goes wrong, something is seriously broken.
+ qInstallMsgHandler(oldMessageHandler);
+ QTEST_ASSERT(msg);
+ QTEST_ASSERT(QTest::testLogger);
+ }
+
+ if (handleIgnoredMessage(type, msg))
+ // the message is expected, so just swallow it.
+ return;
+
+ if (type != QtFatalMsg) {
+ if (counter <= 0)
+ return;
+
+ if (!counter.deref()) {
+ QTest::testLogger->addMessage(QAbstractTestLogger::QSystem,
+ "Maximum amount of warnings exceeded. Use -maxwarnings to override.");
+ return;
+ }
+ }
+
+ switch (type) {
+ case QtDebugMsg:
+ QTest::testLogger->addMessage(QAbstractTestLogger::QDebug, msg);
+ break;
+ case QtCriticalMsg:
+ QTest::testLogger->addMessage(QAbstractTestLogger::QSystem, msg);
+ break;
+ case QtWarningMsg:
+ QTest::testLogger->addMessage(QAbstractTestLogger::QWarning, msg);
+ break;
+ case QtFatalMsg:
+ QTest::testLogger->addMessage(QAbstractTestLogger::QFatal, msg);
+ /* Right now, we're inside the custom message handler and we're
+ * being qt_message_output in qglobal.cpp. After we return from
+ * this function, it will proceed with calling exit() and abort()
+ * and hence crash. Therefore, we call these logging functions such
+ * that we wrap up nicely, and in particular produce well-formed XML. */
+ QTestResult::addFailure("Received a fatal error.", "Unknown file", 0);
+ QTestLog::leaveTestFunction();
+ QTestLog::stopLogging();
+ break;
+ }
+ }
+
+void initLogger()
+{
+ switch (QTest::logMode) {
+ case QTestLog::Plain:
+ QTest::testLogger = new QPlainTestLogger;
+ break;
+ case QTestLog::XML:{
+ if(QTest::flushMode == QTestLog::FLushOn)
+ QTest::testLogger = new QXmlTestLogger(QXmlTestLogger::Complete);
+ else
+ QTest::testLogger = new QTestLogger(QTestLogger::TLF_XML);
+ break;
+ }case QTestLog::LightXML:{
+ if(QTest::flushMode == QTestLog::FLushOn)
+ QTest::testLogger = new QXmlTestLogger(QXmlTestLogger::Light);
+ else
+ QTest::testLogger = new QTestLogger(QTestLogger::TLF_LightXml);
+ break;
+ }case QTestLog::XunitXML:
+ QTest::testLogger = new QTestLogger(QTestLogger::TLF_XunitXml);
+ }
+}
+
+}
+
+QTestLog::QTestLog()
+{
+}
+
+QTestLog::~QTestLog()
+{
+}
+
+void QTestLog::enterTestFunction(const char* function)
+{
+ QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(function);
+
+ QTest::testLogger->enterTestFunction(function);
+}
+
+int QTestLog::unhandledIgnoreMessages()
+{
+ int i = 0;
+ QTest::IgnoreResultList *list = QTest::ignoreResultList;
+ while (list) {
+ ++i;
+ list = list->next;
+ }
+ return i;
+}
+
+void QTestLog::leaveTestFunction()
+{
+ QTEST_ASSERT(QTest::testLogger);
+
+ QTest::IgnoreResultList::clearList(QTest::ignoreResultList);
+ QTest::testLogger->leaveTestFunction();
+}
+
+void QTestLog::printUnhandledIgnoreMessages()
+{
+ QTEST_ASSERT(QTest::testLogger);
+
+ char msg[1024];
+ QTest::IgnoreResultList *list = QTest::ignoreResultList;
+ while (list) {
+ QTest::qt_snprintf(msg, 1024, "Did not receive message: \"%s\"", list->msg);
+ QTest::testLogger->addMessage(QAbstractTestLogger::Info, msg);
+
+ list = list->next;
+ }
+}
+
+void QTestLog::addPass(const char *msg)
+{
+ QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(msg);
+
+ QTest::testLogger->addIncident(QAbstractTestLogger::Pass, msg);
+}
+
+void QTestLog::addFail(const char *msg, const char *file, int line)
+{
+ QTEST_ASSERT(QTest::testLogger);
+
+ QTest::testLogger->addIncident(QAbstractTestLogger::Fail, msg, file, line);
+}
+
+void QTestLog::addXFail(const char *msg, const char *file, int line)
+{
+ QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(msg);
+ QTEST_ASSERT(file);
+
+ QTest::testLogger->addIncident(QAbstractTestLogger::XFail, msg, file, line);
+}
+
+void QTestLog::addXPass(const char *msg, const char *file, int line)
+{
+ QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(msg);
+ QTEST_ASSERT(file);
+
+ QTest::testLogger->addIncident(QAbstractTestLogger::XPass, msg, file, line);
+}
+
+void QTestLog::addSkip(const char *msg, QTest::SkipMode /*mode*/,
+ const char *file, int line)
+{
+ QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(msg);
+ QTEST_ASSERT(file);
+
+ QTest::testLogger->addMessage(QAbstractTestLogger::Skip, msg, file, line);
+}
+
+void QTestLog::addBenchmarkResult(const QBenchmarkResult &result)
+{
+ QTEST_ASSERT(QTest::testLogger);
+ QTest::testLogger->addBenchmarkResult(result);
+}
+
+void QTestLog::startLogging(unsigned int randomSeed)
+{
+ QTEST_ASSERT(!QTest::testLogger);
+ QTest::initLogger();
+ QTest::testLogger->registerRandomSeed(randomSeed);
+ QTest::testLogger->startLogging();
+ QTest::oldMessageHandler = qInstallMsgHandler(QTest::messageHandler);
+}
+
+void QTestLog::startLogging()
+{
+ QTEST_ASSERT(!QTest::testLogger);
+ QTest::initLogger();
+ QTest::testLogger->startLogging();
+ QTest::oldMessageHandler = qInstallMsgHandler(QTest::messageHandler);
+}
+
+void QTestLog::stopLogging()
+{
+ qInstallMsgHandler(QTest::oldMessageHandler);
+
+ QTEST_ASSERT(QTest::testLogger);
+ QTest::testLogger->stopLogging();
+ delete QTest::testLogger;
+ QTest::testLogger = 0;
+}
+
+void QTestLog::warn(const char *msg)
+{
+ QTEST_ASSERT(QTest::testLogger);
+ QTEST_ASSERT(msg);
+
+ QTest::testLogger->addMessage(QAbstractTestLogger::Warn, msg);
+}
+
+void QTestLog::info(const char *msg, const char *file, int line)
+{
+ QTEST_ASSERT(msg);
+
+ if (QTest::testLogger)
+ QTest::testLogger->addMessage(QAbstractTestLogger::Info, msg, file, line);
+}
+
+void QTestLog::setLogMode(LogMode mode)
+{
+ QTest::logMode = mode;
+}
+
+QTestLog::LogMode QTestLog::logMode()
+{
+ return QTest::logMode;
+}
+
+void QTestLog::setVerboseLevel(int level)
+{
+ QTest::verbosity = level;
+}
+
+int QTestLog::verboseLevel()
+{
+ return QTest::verbosity;
+}
+
+void QTestLog::addIgnoreMessage(QtMsgType type, const char *msg)
+{
+ QTest::IgnoreResultList *item = new QTest::IgnoreResultList(type, msg);
+
+ QTest::IgnoreResultList *list = QTest::ignoreResultList;
+ if (!list) {
+ QTest::ignoreResultList = item;
+ return;
+ }
+ while (list->next)
+ list = list->next;
+ list->next = item;
+}
+
+void QTestLog::redirectOutput(const char *fileName)
+{
+ QTEST_ASSERT(fileName);
+
+ QTest::outFile = fileName;
+}
+
+const char *QTestLog::outputFileName()
+{
+ return QTest::outFile;
+}
+
+void QTestLog::setMaxWarnings(int m)
+{
+ QTest::maxWarnings = m <= 0 ? INT_MAX : m + 2;
+}
+
+void QTestLog::setFlushMode(FlushMode mode)
+{
+ QTest::flushMode = mode;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h
new file mode 100644
index 0000000000..a892d3d27c
--- /dev/null
+++ b/src/testlib/qtestlog_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTLOG_P_H
+#define QTESTLOG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtTest/qtest_global.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBenchmarkResult;
+
+class Q_TESTLIB_EXPORT QTestLog
+{
+public:
+ enum LogMode { Plain = 0, XML, LightXML, XunitXML };
+ enum FlushMode { NoFlush = 0, FLushOn };
+
+ static void enterTestFunction(const char* function);
+ static void leaveTestFunction();
+
+ static void addPass(const char *msg);
+ static void addFail(const char *msg, const char *file, int line);
+ static void addXFail(const char *msg, const char *file, int line);
+ static void addXPass(const char *msg, const char *file, int line);
+ static void addSkip(const char *msg, QTest::SkipMode mode,
+ const char *file, int line);
+ static void addBenchmarkResult(const QBenchmarkResult &result);
+ static void addIgnoreMessage(QtMsgType type, const char *msg);
+ static int unhandledIgnoreMessages();
+ static void printUnhandledIgnoreMessages();
+
+ static void warn(const char *msg);
+ static void info(const char *msg, const char *file, int line);
+
+ static void startLogging();
+ static void startLogging(unsigned int randomSeed);
+ static void stopLogging();
+
+ static void setLogMode(LogMode mode);
+ static LogMode logMode();
+
+ static void setVerboseLevel(int level);
+ static int verboseLevel();
+
+ static void redirectOutput(const char *fileName);
+ static const char *outputFileName();
+
+ static void setMaxWarnings(int max);
+
+ static void setFlushMode(FlushMode mode);
+private:
+ QTestLog();
+ ~QTestLog();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qtestlogger.cpp b/src/testlib/qtestlogger.cpp
new file mode 100644
index 0000000000..86826f8a97
--- /dev/null
+++ b/src/testlib/qtestlogger.cpp
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtestlogger_p.h"
+#include "qtestelement.h"
+#include "qtestxunitstreamer.h"
+#include "qtestxmlstreamer.h"
+#include "qtestlightxmlstreamer.h"
+#include "qtestfilelogger.h"
+
+#include "QtTest/qtestcase.h"
+#include "QtTest/private/qtestresult_p.h"
+#include "QtTest/private/qbenchmark_p.h"
+
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+QTestLogger::QTestLogger(int fm)
+ :listOfTestcases(0), currentLogElement(0), errorLogElement(0),
+ logFormatter(0), format( (TestLoggerFormat)fm ), filelogger(new QTestFileLogger),
+ testCounter(0), passCounter(0),
+ failureCounter(0), errorCounter(0),
+ warningCounter(0), skipCounter(0),
+ systemCounter(0), qdebugCounter(0),
+ qwarnCounter(0), qfatalCounter(0),
+ infoCounter(0), randomSeed_(0),
+ hasRandomSeed_(false)
+{
+}
+
+QTestLogger::~QTestLogger()
+{
+ if(format == TLF_XunitXml)
+ delete currentLogElement;
+ else
+ delete listOfTestcases;
+
+ delete logFormatter;
+ delete filelogger;
+}
+
+void QTestLogger::startLogging()
+{
+ switch(format){
+ case TLF_LightXml:{
+ logFormatter = new QTestLightXmlStreamer;
+ filelogger->init();
+ break;
+ }case TLF_XML:{
+ logFormatter = new QTestXmlStreamer;
+ filelogger->init();
+ break;
+ }case TLF_XunitXml:{
+ logFormatter = new QTestXunitStreamer;
+ delete errorLogElement;
+ errorLogElement = new QTestElement(QTest::LET_SystemError);
+ filelogger->init();
+ break;
+ }
+ }
+
+ logFormatter->setLogger(this);
+ logFormatter->startStreaming();
+}
+
+void QTestLogger::stopLogging()
+{
+ QTestElement *iterator = listOfTestcases;
+
+ if(format == TLF_XunitXml ){
+ char buf[10];
+
+ currentLogElement = new QTestElement(QTest::LET_TestSuite);
+ currentLogElement->addAttribute(QTest::AI_Name, QTestResult::currentTestObjectName());
+
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", testCounter);
+ currentLogElement->addAttribute(QTest::AI_Tests, buf);
+
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", failureCounter);
+ currentLogElement->addAttribute(QTest::AI_Failures, buf);
+
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", errorCounter);
+ currentLogElement->addAttribute(QTest::AI_Errors, buf);
+
+ QTestElement *property;
+ QTestElement *properties = new QTestElement(QTest::LET_Properties);
+
+ property = new QTestElement(QTest::LET_Property);
+ property->addAttribute(QTest::AI_Name, "QTestVersion");
+ property->addAttribute(QTest::AI_PropertyValue, QTEST_VERSION_STR);
+ properties->addLogElement(property);
+
+ property = new QTestElement(QTest::LET_Property);
+ property->addAttribute(QTest::AI_Name, "QtVersion");
+ property->addAttribute(QTest::AI_PropertyValue, qVersion());
+ properties->addLogElement(property);
+
+ if (hasRandomSeed()) {
+ property = new QTestElement(QTest::LET_Property);
+ property->addAttribute(QTest::AI_Name, "RandomSeed");
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", randomSeed());
+ property->addAttribute(QTest::AI_PropertyValue, buf);
+ properties->addLogElement(property);
+ }
+
+ currentLogElement->addLogElement(properties);
+
+ currentLogElement->addLogElement(iterator);
+
+ /* For correct indenting, make sure every testcase knows its parent */
+ QTestElement* testcase = iterator;
+ while (testcase) {
+ testcase->setParent(currentLogElement);
+ testcase = testcase->nextElement();
+ }
+
+ currentLogElement->addLogElement(errorLogElement);
+
+ QTestElement *it = currentLogElement;
+ logFormatter->output(it);
+ }else{
+ logFormatter->output(iterator);
+ }
+
+ logFormatter->stopStreaming();
+}
+
+void QTestLogger::enterTestFunction(const char *function)
+{
+ char buf[1024];
+ QTest::qt_snprintf(buf, sizeof(buf), "Entered test-function: %s\n", function);
+ filelogger->flush(buf);
+
+ currentLogElement = new QTestElement(QTest::LET_TestCase);
+ currentLogElement->addAttribute(QTest::AI_Name, function);
+ currentLogElement->addToList(&listOfTestcases);
+
+ ++testCounter;
+}
+
+void QTestLogger::leaveTestFunction()
+{
+}
+
+void QTestLogger::addIncident(IncidentTypes type, const char *description,
+ const char *file, int line)
+{
+ const char *typeBuf = 0;
+ char buf[100];
+
+ switch (type) {
+ case QAbstractTestLogger::XPass:
+ ++failureCounter;
+ typeBuf = "xpass";
+ break;
+ case QAbstractTestLogger::Pass:
+ ++passCounter;
+ typeBuf = "pass";
+ break;
+ case QAbstractTestLogger::XFail:
+ ++passCounter;
+ typeBuf = "xfail";
+ break;
+ case QAbstractTestLogger::Fail:
+ ++failureCounter;
+ typeBuf = "fail";
+ break;
+ default:
+ typeBuf = "??????";
+ break;
+ }
+
+ if (type == QAbstractTestLogger::Fail || type == QAbstractTestLogger::XPass
+ || ((format != TLF_XunitXml) && (type == QAbstractTestLogger::XFail))) {
+ QTestElement *failureElement = new QTestElement(QTest::LET_Failure);
+ failureElement->addAttribute(QTest::AI_Result, typeBuf);
+ if(file)
+ failureElement->addAttribute(QTest::AI_File, file);
+ else
+ failureElement->addAttribute(QTest::AI_File, "");
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", line);
+ failureElement->addAttribute(QTest::AI_Line, buf);
+ failureElement->addAttribute(QTest::AI_Description, description);
+ addTag(failureElement);
+ currentLogElement->addLogElement(failureElement);
+ }
+
+ /*
+ Only one result can be shown for the whole testfunction.
+ Check if we currently have a result, and if so, overwrite it
+ iff the new result is worse.
+ */
+ QTestElementAttribute* resultAttr =
+ const_cast<QTestElementAttribute*>(currentLogElement->attribute(QTest::AI_Result));
+ if (resultAttr) {
+ const char* oldResult = resultAttr->value();
+ bool overwrite = false;
+ if (!strcmp(oldResult, "pass")) {
+ overwrite = true;
+ }
+ else if (!strcmp(oldResult, "xfail")) {
+ overwrite = (type == QAbstractTestLogger::XPass || type == QAbstractTestLogger::Fail);
+ }
+ else if (!strcmp(oldResult, "xpass")) {
+ overwrite = (type == QAbstractTestLogger::Fail);
+ }
+ if (overwrite) {
+ resultAttr->setPair(QTest::AI_Result, typeBuf);
+ }
+ }
+ else {
+ currentLogElement->addAttribute(QTest::AI_Result, typeBuf);
+ }
+
+ if(file)
+ currentLogElement->addAttribute(QTest::AI_File, file);
+ else
+ currentLogElement->addAttribute(QTest::AI_File, "");
+
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", line);
+ currentLogElement->addAttribute(QTest::AI_Line, buf);
+
+ /*
+ Since XFAIL does not add a failure to the testlog in xunitxml, add a message, so we still
+ have some information about the expected failure.
+ */
+ if (format == TLF_XunitXml && type == QAbstractTestLogger::XFail) {
+ QTestLogger::addMessage(QAbstractTestLogger::Info, description, file, line);
+ }
+}
+
+void QTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
+{
+ QTestElement *benchmarkElement = new QTestElement(QTest::LET_Benchmark);
+// printf("element %i", benchmarkElement->elementType());
+
+ benchmarkElement->addAttribute(
+ QTest::AI_Metric,
+ QTest::benchmarkMetricName(QBenchmarkTestMethodData::current->result.metric));
+ benchmarkElement->addAttribute(QTest::AI_Tag, result.context.tag.toAscii().data());
+ benchmarkElement->addAttribute(QTest::AI_Value, QByteArray::number(result.value).constData());
+
+ char buf[100];
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", result.iterations);
+ benchmarkElement->addAttribute(QTest::AI_Iterations, buf);
+ currentLogElement->addLogElement(benchmarkElement);
+}
+
+void QTestLogger::addTag(QTestElement* element)
+{
+ const char *tag = QTestResult::currentDataTag();
+ const char *gtag = QTestResult::currentGlobalDataTag();
+ const char *filler = (tag && gtag) ? ":" : "";
+ if ((!tag || !tag[0]) && (!gtag || !gtag[0])) {
+ return;
+ }
+
+ if (!tag) {
+ tag = "";
+ }
+ if (!gtag) {
+ gtag = "";
+ }
+
+ QTestCharBuffer buf;
+ QTest::qt_asprintf(&buf, "%s%s%s", gtag, filler, tag);
+ element->addAttribute(QTest::AI_Tag, buf.constData());
+}
+
+void QTestLogger::addMessage(MessageTypes type, const char *message, const char *file, int line)
+{
+ QTestElement *errorElement = new QTestElement(QTest::LET_Error);
+ const char *typeBuf = 0;
+
+ switch (type) {
+ case QAbstractTestLogger::Warn:
+ ++warningCounter;
+ typeBuf = "warn";
+ break;
+ case QAbstractTestLogger::QSystem:
+ ++systemCounter;
+ typeBuf = "system";
+ break;
+ case QAbstractTestLogger::QDebug:
+ ++qdebugCounter;
+ typeBuf = "qdebug";
+ break;
+ case QAbstractTestLogger::QWarning:
+ ++qwarnCounter;
+ typeBuf = "qwarn";
+ break;
+ case QAbstractTestLogger::QFatal:
+ ++qfatalCounter;
+ typeBuf = "qfatal";
+ break;
+ case QAbstractTestLogger::Skip:
+ ++skipCounter;
+ typeBuf = "skip";
+ break;
+ case QAbstractTestLogger::Info:
+ ++infoCounter;
+ typeBuf = "info";
+ break;
+ default:
+ typeBuf = "??????";
+ break;
+ }
+
+ errorElement->addAttribute(QTest::AI_Type, typeBuf);
+ errorElement->addAttribute(QTest::AI_Description, message);
+ addTag(errorElement);
+
+ if(file)
+ errorElement->addAttribute(QTest::AI_File, file);
+ else
+ errorElement->addAttribute(QTest::AI_File, "");
+
+ char buf[100];
+ QTest::qt_snprintf(buf, sizeof(buf), "%i", line);
+ errorElement->addAttribute(QTest::AI_Line, buf);
+
+ currentLogElement->addLogElement(errorElement);
+ ++errorCounter;
+
+ // 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);
+ errorLogElement->addLogElement(systemErrorElement);
+ }
+}
+
+void QTestLogger::setLogFormat(TestLoggerFormat fm)
+{
+ format = fm;
+}
+
+QTestLogger::TestLoggerFormat QTestLogger::logFormat()
+{
+ return format;
+}
+
+int QTestLogger::passCount() const
+{
+ return passCounter;
+}
+
+int QTestLogger::failureCount() const
+{
+ return failureCounter;
+}
+
+int QTestLogger::errorCount() const
+{
+ return errorCounter;
+}
+
+int QTestLogger::warningCount() const
+{
+ return warningCounter;
+}
+
+int QTestLogger::skipCount() const
+{
+ return skipCounter;
+}
+
+int QTestLogger::systemCount() const
+{
+ return systemCounter;
+}
+
+int QTestLogger::qdebugCount() const
+{
+ return qdebugCounter;
+}
+
+int QTestLogger::qwarnCount() const
+{
+ return qwarnCounter;
+}
+
+int QTestLogger::qfatalCount() const
+{
+ return qfatalCounter;
+}
+
+int QTestLogger::infoCount() const
+{
+ return infoCounter;
+}
+
+void QTestLogger::registerRandomSeed(unsigned int seed)
+{
+ randomSeed_ = seed;
+ hasRandomSeed_ = true;
+}
+
+unsigned int QTestLogger::randomSeed() const
+{
+ return randomSeed_;
+}
+
+bool QTestLogger::hasRandomSeed() const
+{
+ return hasRandomSeed_;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/testlib/qtestlogger_p.h b/src/testlib/qtestlogger_p.h
new file mode 100644
index 0000000000..d8867de286
--- /dev/null
+++ b/src/testlib/qtestlogger_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTLOGGER_P_H
+#define QTESTLOGGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtTest/private/qabstracttestlogger_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTestBasicStreamer;
+class QTestElement;
+class QTestFileLogger;
+
+class QTestLogger : public QAbstractTestLogger
+{
+ public:
+ QTestLogger(int fm = 0);
+ ~QTestLogger();
+
+ enum TestLoggerFormat
+ {
+ TLF_XML = 0,
+ TLF_LightXml = 1,
+ TLF_XunitXml = 2
+ };
+
+ void startLogging();
+ void stopLogging();
+
+ void enterTestFunction(const char *function);
+ void leaveTestFunction();
+
+ void addIncident(IncidentTypes type, const char *description,
+ const char *file = 0, int line = 0);
+ void addBenchmarkResult(const QBenchmarkResult &result);
+ void addTag(QTestElement* element);
+
+ void addMessage(MessageTypes type, const char *message,
+ const char *file = 0, int line = 0);
+
+ void setLogFormat(TestLoggerFormat fm);
+ TestLoggerFormat logFormat();
+
+ int passCount() const;
+ int failureCount() const;
+ int errorCount() const;
+ int warningCount() const;
+ int skipCount() const;
+ int systemCount() const;
+ int qdebugCount() const;
+ int qwarnCount() const;
+ int qfatalCount() const;
+ int infoCount() const;
+ void registerRandomSeed(unsigned int seed);
+ unsigned int randomSeed() const;
+ bool hasRandomSeed() const;
+
+ private:
+ QTestElement *listOfTestcases;
+ QTestElement *currentLogElement;
+ QTestElement *errorLogElement;
+ QTestBasicStreamer *logFormatter;
+ TestLoggerFormat format;
+ QTestFileLogger *filelogger;
+
+ int testCounter;
+ int passCounter;
+ int failureCounter;
+ int errorCounter;
+ int warningCounter;
+ int skipCounter;
+ int systemCounter;
+ int qdebugCounter;
+ int qwarnCounter;
+ int qfatalCounter;
+ int infoCounter;
+ unsigned int randomSeed_;
+ bool hasRandomSeed_;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTESTLOGGER_P_H
diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h
new file mode 100644
index 0000000000..5abb019786
--- /dev/null
+++ b/src/testlib/qtestmouse.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if !defined(QTESTMOUSE_H)
+#define QTESTMOUSE_H
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+#include <QtTest/qtest_global.h>
+#include <QtTest/qtestassert.h>
+#include <QtTest/qtestsystem.h>
+#include <QtTest/qtestspontaneevent.h>
+
+#include <QtCore/qpoint.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest
+{
+ enum MouseAction { MousePress, MouseRelease, MouseClick, MouseDClick, MouseMove };
+
+ static void mouseEvent(MouseAction action, QWidget *widget, Qt::MouseButton button,
+ Qt::KeyboardModifiers stateKey, QPoint pos, int delay=-1)
+ {
+ QTEST_ASSERT(widget);
+ extern int Q_TESTLIB_EXPORT defaultMouseDelay();
+
+ if (delay == -1 || delay < defaultMouseDelay())
+ delay = defaultMouseDelay();
+ if(delay > 0)
+ QTest::qWait(delay);
+
+ if (pos.isNull())
+ pos = widget->rect().center();
+
+ if (action == MouseClick) {
+ mouseEvent(MousePress, widget, button, stateKey, pos);
+ mouseEvent(MouseRelease, widget, button, stateKey, pos);
+ return;
+ }
+
+ QTEST_ASSERT(button == Qt::NoButton || button & Qt::MouseButtonMask);
+ QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask);
+
+ stateKey &= static_cast<unsigned int>(Qt::KeyboardModifierMask);
+
+ QMouseEvent me(QEvent::User, QPoint(), Qt::LeftButton, button, stateKey);
+ switch (action)
+ {
+ case MousePress:
+ me = QMouseEvent(QEvent::MouseButtonPress, pos, widget->mapToGlobal(pos), button, button, stateKey);
+ break;
+ case MouseRelease:
+ me = QMouseEvent(QEvent::MouseButtonRelease, pos, widget->mapToGlobal(pos), button, 0, stateKey);
+ break;
+ case MouseDClick:
+ me = QMouseEvent(QEvent::MouseButtonDblClick, pos, widget->mapToGlobal(pos), button, button, stateKey);
+ break;
+ case MouseMove:
+ QCursor::setPos(widget->mapToGlobal(pos));
+#ifdef QT_MAC_USE_COCOA
+ QTest::qWait(20);
+#else
+ qApp->processEvents();
+#endif
+ return;
+ default:
+ QTEST_ASSERT(false);
+ }
+ QSpontaneKeyEvent::setSpontaneous(&me);
+ if (!qApp->notify(widget, &me)) {
+ static const char *mouseActionNames[] =
+ { "MousePress", "MouseRelease", "MouseClick", "MouseDClick", "MouseMove" };
+ QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget");
+ QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toAscii().data());
+ }
+
+ }
+
+ inline void mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { mouseEvent(MousePress, widget, button, stateKey, pos, delay); }
+ inline void mouseRelease(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { mouseEvent(MouseRelease, widget, button, stateKey, pos, delay); }
+ inline void mouseClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { mouseEvent(MouseClick, widget, button, stateKey, pos, delay); }
+ inline void mouseDClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0,
+ QPoint pos = QPoint(), int delay=-1)
+ { mouseEvent(MouseDClick, widget, button, stateKey, pos, delay); }
+ inline void mouseMove(QWidget *widget, QPoint pos = QPoint(), int delay=-1)
+ { mouseEvent(MouseMove, widget, Qt::NoButton, 0, pos, delay); }
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTESTMOUSE_H
diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp
new file mode 100644
index 0000000000..d5d314aa7e
--- /dev/null
+++ b/src/testlib/qtestresult.cpp
@@ -0,0 +1,352 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qtestresult_p.h"
+#include <QtCore/qglobal.h>
+
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/qtestdata.h"
+#include "QtTest/qtestassert.h"
+
+#include <stdio.h>
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest
+{
+ static QTestData *currentTestData = 0;
+ static QTestData *currentGlobalTestData = 0;
+ static const char *currentTestFunc = 0;
+ static const char *currentTestObjectName = 0;
+ static bool failed = false;
+ static bool dataFailed = false;
+ static bool skipCurrentTest = false;
+ static QTestResult::TestLocation location = QTestResult::NoWhere;
+
+ static int fails = 0;
+ static int passes = 0;
+ static int skips = 0;
+
+ static const char *expectFailComment = 0;
+ static int expectFailMode = 0;
+}
+
+void QTestResult::reset()
+{
+ QTest::currentTestData = 0;
+ QTest::currentGlobalTestData = 0;
+ QTest::currentTestFunc = 0;
+ QTest::currentTestObjectName = 0;
+ QTest::failed = false;
+ QTest::dataFailed = false;
+ QTest::location = QTestResult::NoWhere;
+
+ QTest::fails = 0;
+ QTest::passes = 0;
+ QTest::skips = 0;
+
+ QTest::expectFailComment = 0;
+ QTest::expectFailMode = 0;
+}
+
+bool QTestResult::allDataPassed()
+{
+ return !QTest::failed;
+}
+
+bool QTestResult::currentTestFailed()
+{
+ return QTest::dataFailed;
+}
+
+QTestData *QTestResult::currentGlobalTestData()
+{
+ return QTest::currentGlobalTestData;
+}
+
+QTestData *QTestResult::currentTestData()
+{
+ return QTest::currentTestData;
+}
+
+void QTestResult::setCurrentGlobalTestData(QTestData *data)
+{
+ QTest::currentGlobalTestData = data;
+}
+
+void QTestResult::setCurrentTestData(QTestData *data)
+{
+ QTest::currentTestData = data;
+ QTest::dataFailed = false;
+}
+
+void QTestResult::setCurrentTestFunction(const char *func)
+{
+ QTest::currentTestFunc = func;
+ QTest::failed = false;
+ if (!func)
+ QTest::location = NoWhere;
+ if (func)
+ QTestLog::enterTestFunction(func);
+}
+
+static void clearExpectFail()
+{
+ QTest::expectFailMode = 0;
+ delete [] const_cast<char *>(QTest::expectFailComment);
+ QTest::expectFailComment = 0;
+}
+
+void QTestResult::finishedCurrentTestFunction()
+{
+ if (!QTest::failed && QTestLog::unhandledIgnoreMessages()) {
+ QTestLog::printUnhandledIgnoreMessages();
+ addFailure("Not all expected messages were received", 0, 0);
+ }
+
+ if (!QTest::failed && !QTest::skipCurrentTest) {
+ QTestLog::addPass("");
+ ++QTest::passes;
+ }
+ QTest::currentTestFunc = 0;
+ QTest::failed = false;
+ QTest::dataFailed = false;
+ QTest::location = NoWhere;
+
+ QTestLog::leaveTestFunction();
+
+ clearExpectFail();
+}
+
+const char *QTestResult::currentTestFunction()
+{
+ return QTest::currentTestFunc;
+}
+
+const char *QTestResult::currentDataTag()
+{
+ return QTest::currentTestData ? QTest::currentTestData->dataTag()
+ : static_cast<const char *>(0);
+}
+
+const char *QTestResult::currentGlobalDataTag()
+{
+ return QTest::currentGlobalTestData ? QTest::currentGlobalTestData->dataTag()
+ : static_cast<const char *>(0);
+}
+
+static bool isExpectFailData(const char *dataIndex)
+{
+ if (!dataIndex || dataIndex[0] == '\0')
+ return true;
+ if (!QTest::currentTestData)
+ return false;
+ if (strcmp(dataIndex, QTest::currentTestData->dataTag()) == 0)
+ return true;
+ return false;
+}
+
+bool QTestResult::expectFail(const char *dataIndex, const char *comment,
+ QTest::TestFailMode mode, const char *file, int line)
+{
+ QTEST_ASSERT(comment);
+ QTEST_ASSERT(mode > 0);
+
+ if (!isExpectFailData(dataIndex)) {
+ delete[] comment;
+ return true; // we don't care
+ }
+
+ if (QTest::expectFailMode) {
+ delete[] comment;
+ clearExpectFail();
+ addFailure("Already expecting a fail", file, line);
+ return false;
+ }
+
+ QTest::expectFailMode = mode;
+ QTest::expectFailComment = comment;
+ return true;
+}
+
+static bool checkStatement(bool statement, const char *msg, const char *file, int line)
+{
+ if (statement) {
+ if (QTest::expectFailMode) {
+ QTestLog::addXPass(msg, file, line);
+ bool doContinue = (QTest::expectFailMode == QTest::Continue);
+ clearExpectFail();
+ QTest::failed = true;
+ ++QTest::fails;
+ return doContinue;
+ }
+ return true;
+ }
+
+ if (QTest::expectFailMode) {
+ QTestLog::addXFail(QTest::expectFailComment, file, line);
+ bool doContinue = (QTest::expectFailMode == QTest::Continue);
+ clearExpectFail();
+ return doContinue;
+ }
+
+ QTestResult::addFailure(msg, file, line);
+ return false;
+}
+
+bool QTestResult::verify(bool statement, const char *statementStr,
+ const char *description, const char *file, int line)
+{
+ char msg[1024];
+
+ if (QTestLog::verboseLevel() >= 2) {
+ QTest::qt_snprintf(msg, 1024, "QVERIFY(%s)", statementStr);
+ QTestLog::info(msg, file, line);
+ }
+
+ QTest::qt_snprintf(msg, 1024, "'%s' returned FALSE. (%s)", statementStr, description);
+
+ return checkStatement(statement, msg, file, line);
+}
+
+bool QTestResult::compare(bool success, const char *msg, const char *file, int line)
+{
+ if (QTestLog::verboseLevel() >= 2) {
+ QTestLog::info(msg, file, line);
+ }
+
+ return checkStatement(success, msg, file, line);
+}
+
+bool QTestResult::compare(bool success, const char *msg, char *val1, char *val2,
+ const char *actual, const char *expected, const char *file, int line)
+{
+ QTEST_ASSERT(expected);
+ QTEST_ASSERT(actual);
+
+ if (!val1 && !val2)
+ return compare(success, msg, file, line);
+
+ char buf[1024];
+ QTest::qt_snprintf(buf, 1024, "%s\n Actual (%s): %s\n Expected (%s): %s", msg,
+ actual, val1 ? val1 : "<null>",
+ expected, val2 ? val2 : "<null>");
+ delete [] val1;
+ delete [] val2;
+ return compare(success, buf, file, line);
+}
+
+void QTestResult::addFailure(const char *message, const char *file, int line)
+{
+ clearExpectFail();
+
+ QTestLog::addFail(message, file, line);
+ QTest::failed = true;
+ QTest::dataFailed = true;
+ ++QTest::fails;
+}
+
+void QTestResult::addSkip(const char *message, QTest::SkipMode mode,
+ const char *file, int line)
+{
+ clearExpectFail();
+
+ QTestLog::addSkip(message, mode, file, line);
+ ++QTest::skips;
+}
+
+QTestResult::TestLocation QTestResult::currentTestLocation()
+{
+ return QTest::location;
+}
+
+void QTestResult::setCurrentTestLocation(TestLocation loc)
+{
+ QTest::location = loc;
+}
+
+void QTestResult::setCurrentTestObject(const char *name)
+{
+ QTest::currentTestObjectName = name;
+}
+
+const char *QTestResult::currentTestObjectName()
+{
+ return QTest::currentTestObjectName ? QTest::currentTestObjectName : "";
+}
+
+int QTestResult::passCount()
+{
+ return QTest::passes;
+}
+
+int QTestResult::failCount()
+{
+ return QTest::fails;
+}
+
+int QTestResult::skipCount()
+{
+ return QTest::skips;
+}
+
+void QTestResult::ignoreMessage(QtMsgType type, const char *msg)
+{
+ QTestLog::addIgnoreMessage(type, msg);
+}
+
+bool QTestResult::testFailed()
+{
+ return QTest::failed;
+}
+
+void QTestResult::setSkipCurrentTest(bool value)
+{
+ QTest::skipCurrentTest = value;
+}
+
+bool QTestResult::skipCurrentTest()
+{
+ return QTest::skipCurrentTest;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtestresult_p.h b/src/testlib/qtestresult_p.h
new file mode 100644
index 0000000000..7ff120af77
--- /dev/null
+++ b/src/testlib/qtestresult_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTRESULT_P_H
+#define QTESTRESULT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtTest/qtest_global.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTestResultPrivate;
+class QTestData;
+
+class Q_TESTLIB_EXPORT QTestResult
+{
+public:
+ enum TestLocation { NoWhere = 0, DataFunc = 1, InitFunc = 2, Func = 3, CleanupFunc = 4 };
+
+ static const char *currentTestObjectName();
+ static bool currentTestFailed();
+ static bool allDataPassed();
+ static QTestData *currentTestData();
+ static QTestData *currentGlobalTestData();
+ static const char *currentTestFunction();
+ static TestLocation currentTestLocation();
+ static const char *currentDataTag();
+ static const char *currentGlobalDataTag();
+ static void finishedCurrentTestFunction();
+ static void reset();
+
+ static int passCount();
+ static int failCount();
+ static int skipCount();
+
+ static void ignoreMessage(QtMsgType type, const char *msg);
+
+ static void addFailure(const char *message, const char *file, int line);
+ static bool compare(bool success, const char *msg, const char *file, int line);
+ static bool compare(bool success, const char *msg, char *val1, char *val2,
+ const char *actual, const char *expected, const char *file, int line);
+
+ static void setCurrentGlobalTestData(QTestData *data);
+ static void setCurrentTestData(QTestData *data);
+ static void setCurrentTestFunction(const char *func);
+ static void setCurrentTestLocation(TestLocation loc);
+ static void setCurrentTestObject(const char *name);
+ static void addSkip(const char *message, QTest::SkipMode mode,
+ const char *file, int line);
+ static bool expectFail(const char *dataIndex, const char *comment,
+ QTest::TestFailMode mode, const char *file, int line);
+ static bool verify(bool statement, const char *statementStr, const char *extraInfo,
+ const char *file, int line);
+ static bool testFailed();
+ static void setSkipCurrentTest(bool value);
+ static bool skipCurrentTest();
+
+private:
+ Q_DISABLE_COPY(QTestResult)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qtestspontaneevent.h b/src/testlib/qtestspontaneevent.h
new file mode 100644
index 0000000000..0d8b2aa625
--- /dev/null
+++ b/src/testlib/qtestspontaneevent.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTSPONTANEEVENT_H
+#define QTESTSPONTANEEVENT_H
+
+#include <QtCore/qcoreevent.h>
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+#ifndef QTEST_NO_SIZEOF_CHECK
+template <int>
+class QEventSizeOfChecker
+{
+private:
+ QEventSizeOfChecker() {}
+};
+
+template <>
+class QEventSizeOfChecker<sizeof(QEvent)>
+{
+public:
+ QEventSizeOfChecker() {}
+};
+#endif
+
+class QSpontaneKeyEvent
+{
+public:
+ void setSpontaneous() { spont = 1; }
+ bool spontaneous() { return spont; }
+ virtual void dummyFunc() {}
+ virtual ~QSpontaneKeyEvent() {}
+
+#ifndef QTEST_NO_SIZEOF_CHECK
+ inline void ifYouGetCompileErrorHereYouUseWrongQt()
+ {
+ // this is a static assert in case QEvent changed in Qt
+ QEventSizeOfChecker<sizeof(QSpontaneKeyEvent)> dummy;
+ }
+#endif
+
+ static inline void setSpontaneous(QEvent *ev)
+ {
+ // use a union instead of a reinterpret_cast to prevent alignment warnings
+ union
+ {
+ QSpontaneKeyEvent *skePtr;
+ QEvent *evPtr;
+ } helper;
+
+ helper.evPtr = ev;
+ helper.skePtr->setSpontaneous();
+ }
+
+protected:
+ void *d;
+ ushort t;
+
+private:
+ ushort posted : 1;
+ ushort spont : 1;
+ ushort m_accept : 1;
+ ushort reserved : 13;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtestsystem.h b/src/testlib/qtestsystem.h
new file mode 100644
index 0000000000..11f0f9e38c
--- /dev/null
+++ b/src/testlib/qtestsystem.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTSYSTEM_H
+#define QTESTSYSTEM_H
+
+#include <QtTest/qtestcase.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qelapsedtimer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+class QWidget;
+#ifdef Q_WS_X11
+extern void qt_x11_wait_for_window_manager(QWidget *w);
+#endif
+
+namespace QTest
+{
+ inline static void qWait(int ms)
+ {
+ Q_ASSERT(QCoreApplication::instance());
+
+ QElapsedTimer timer;
+ timer.start();
+ do {
+ QCoreApplication::processEvents(QEventLoop::AllEvents, ms);
+ QTest::qSleep(10);
+ } while (timer.elapsed() < ms);
+ }
+
+ inline static bool qWaitForWindowShown(QWidget *window)
+ {
+#if defined(Q_WS_X11)
+ qt_x11_wait_for_window_manager(window);
+ QCoreApplication::processEvents();
+#elif defined(Q_WS_QWS)
+ Q_UNUSED(window);
+ qWait(100);
+#else
+ Q_UNUSED(window);
+ qWait(50);
+#endif
+ return true;
+ }
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtesttable.cpp b/src/testlib/qtesttable.cpp
new file mode 100644
index 0000000000..df10462898
--- /dev/null
+++ b/src/testlib/qtesttable.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qtesttable_p.h"
+#include "QtTest/qtestdata.h"
+
+#include <QtCore/qmetaobject.h>
+
+#include <string.h>
+
+#include "QtTest/qtestassert.h"
+
+QT_BEGIN_NAMESPACE
+
+class QTestTablePrivate
+{
+public:
+ struct ElementList
+ {
+ ElementList(): elementName(0), elementType(0), next(0) {}
+ const char *elementName;
+ int elementType;
+ ElementList *next;
+ };
+
+ struct DataList
+ {
+ DataList(): data(0), next(0) {}
+ QTestData *data;
+ DataList *next;
+ };
+
+ QTestTablePrivate(): list(0), dataList(0) {}
+ ~QTestTablePrivate();
+
+ ElementList *list;
+ DataList *dataList;
+
+ void append(int elemType, const char *elemName);
+ void append(QTestData *data);
+ ElementList *elementAt(int index);
+ QTestData *dataAt(int index);
+
+ static QTestTable *currentTestTable;
+ static QTestTable *gTable;
+};
+
+QTestTable *QTestTablePrivate::currentTestTable = 0;
+QTestTable *QTestTablePrivate::gTable = 0;
+
+QTestTablePrivate::ElementList *QTestTablePrivate::elementAt(int index)
+{
+ ElementList *iter = list;
+ for (int i = 0; i < index; ++i) {
+ if (!iter)
+ return 0;
+ iter = iter->next;
+ }
+ return iter;
+}
+
+QTestData *QTestTablePrivate::dataAt(int index)
+{
+ DataList *iter = dataList;
+ for (int i = 0; i < index; ++i) {
+ if (!iter)
+ return 0;
+ iter = iter->next;
+ }
+ return iter ? iter->data : 0;
+}
+
+QTestTablePrivate::~QTestTablePrivate()
+{
+ DataList *dit = dataList;
+ while (dit) {
+ DataList *next = dit->next;
+ delete dit->data;
+ delete dit;
+ dit = next;
+ }
+ ElementList *iter = list;
+ while (iter) {
+ ElementList *next = iter->next;
+ delete iter;
+ iter = next;
+ }
+}
+
+void QTestTablePrivate::append(int elemType, const char *elemName)
+{
+ ElementList *item = new ElementList;
+ item->elementName = elemName;
+ item->elementType = elemType;
+ if (!list) {
+ list = item;
+ return;
+ }
+ ElementList *last = list;
+ while (last->next != 0)
+ last = last->next;
+ last->next = item;
+}
+
+void QTestTablePrivate::append(QTestData *data)
+{
+ DataList *item = new DataList;
+ item->data = data;
+ if (!dataList) {
+ dataList = item;
+ return;
+ }
+ DataList *last = dataList;
+ while (last->next != 0)
+ last = last->next;
+ last->next = item;
+}
+
+void QTestTable::addColumn(int type, const char *name)
+{
+ QTEST_ASSERT(type);
+ QTEST_ASSERT(name);
+
+ d->append(type, name);
+}
+
+int QTestTable::elementCount() const
+{
+ QTestTablePrivate::ElementList *item = d->list;
+ int count = 0;
+ while (item) {
+ ++count;
+ item = item->next;
+ }
+ return count;
+}
+
+
+int QTestTable::dataCount() const
+{
+ QTestTablePrivate::DataList *item = d->dataList;
+ int count = 0;
+ while (item) {
+ ++count;
+ item = item->next;
+ }
+ return count;
+}
+
+bool QTestTable::isEmpty() const
+{
+ return !d->list;
+}
+
+QTestData *QTestTable::newData(const char *tag)
+{
+ QTestData *dt = new QTestData(tag, this);
+ d->append(dt);
+ return dt;
+}
+
+QTestTable::QTestTable()
+{
+ d = new QTestTablePrivate;
+ QTestTablePrivate::currentTestTable = this;
+}
+
+QTestTable::~QTestTable()
+{
+ QTestTablePrivate::currentTestTable = 0;
+ delete d;
+}
+
+int QTestTable::elementTypeId(int index) const
+{
+ QTestTablePrivate::ElementList *item = d->elementAt(index);
+ if (!item)
+ return -1;
+ return item->elementType;
+}
+
+const char *QTestTable::dataTag(int index) const
+{
+ QTestTablePrivate::ElementList *item = d->elementAt(index);
+ if (!item)
+ return 0;
+ return item->elementName;
+}
+
+QTestData *QTestTable::testData(int index) const
+{
+ return d->dataAt(index);
+}
+
+int QTestTable::indexOf(const char *elementName) const
+{
+ QTEST_ASSERT(elementName);
+
+ QTestTablePrivate::ElementList *item = d->list;
+ int i = 0;
+ while (item) {
+ if (strcmp(elementName, item->elementName) == 0)
+ return i;
+ item = item->next;
+ ++i;
+ }
+ return -1;
+}
+
+QTestTable *QTestTable::globalTestTable()
+{
+ if (!QTestTablePrivate::gTable)
+ QTestTablePrivate::gTable = new QTestTable();
+ return QTestTablePrivate::gTable;
+}
+
+void QTestTable::clearGlobalTestTable()
+{
+ delete QTestTablePrivate::gTable;
+ QTestTablePrivate::gTable = 0;
+}
+
+QTestTable *QTestTable::currentTestTable()
+{
+ return QTestTablePrivate::currentTestTable;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtesttable_p.h b/src/testlib/qtesttable_p.h
new file mode 100644
index 0000000000..f83550617f
--- /dev/null
+++ b/src/testlib/qtesttable_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions