summaryrefslogtreecommitdiffstats
path: root/src/testlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib')
-rw-r--r--src/testlib/3rdparty/callgrind_p.h147
-rw-r--r--src/testlib/3rdparty/cycle_p.h494
-rw-r--r--src/testlib/3rdparty/valgrind_p.h3926
-rw-r--r--src/testlib/qabstracttestlogger.cpp108
-rw-r--r--src/testlib/qabstracttestlogger_p.h104
-rw-r--r--src/testlib/qasciikey.cpp505
-rw-r--r--src/testlib/qbenchmark.cpp281
-rw-r--r--src/testlib/qbenchmark.h83
-rw-r--r--src/testlib/qbenchmark_p.h193
-rw-r--r--src/testlib/qbenchmarkevent.cpp112
-rw-r--r--src/testlib/qbenchmarkevent_p.h81
-rw-r--r--src/testlib/qbenchmarkmeasurement.cpp142
-rw-r--r--src/testlib/qbenchmarkmeasurement_p.h115
-rw-r--r--src/testlib/qbenchmarkvalgrind.cpp275
-rw-r--r--src/testlib/qbenchmarkvalgrind_p.h93
-rw-r--r--src/testlib/qplaintestlogger.cpp439
-rw-r--r--src/testlib/qplaintestlogger_p.h82
-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/qtest.h251
-rw-r--r--src/testlib/qtest_global.h91
-rw-r--r--src/testlib/qtest_gui.h109
-rw-r--r--src/testlib/qtestaccessible.h165
-rw-r--r--src/testlib/qtestassert.h61
-rw-r--r--src/testlib/qtestcase.cpp1933
-rw-r--r--src/testlib/qtestcase.h340
-rw-r--r--src/testlib/qtestdata.cpp122
-rw-r--r--src/testlib/qtestdata.h97
-rw-r--r--src/testlib/qtestevent.h214
-rw-r--r--src/testlib/qtesteventloop.h136
-rw-r--r--src/testlib/qtestkeyboard.h194
-rw-r--r--src/testlib/qtestlog.cpp364
-rw-r--r--src/testlib/qtestlog_p.h105
-rw-r--r--src/testlib/qtestmouse.h142
-rw-r--r--src/testlib/qtestresult.cpp349
-rw-r--r--src/testlib/qtestresult_p.h112
-rw-r--r--src/testlib/qtestspontaneevent.h118
-rw-r--r--src/testlib/qtestsystem.h74
-rw-r--r--src/testlib/qtesttable.cpp266
-rw-r--r--src/testlib/qtesttable_p.h93
-rw-r--r--src/testlib/qxmltestlogger.cpp264
-rw-r--r--src/testlib/qxmltestlogger_p.h88
-rw-r--r--src/testlib/testlib.pro27
44 files changed, 13329 insertions, 0 deletions
diff --git a/src/testlib/3rdparty/callgrind_p.h b/src/testlib/3rdparty/callgrind_p.h
new file mode 100644
index 0000000..10d7931
--- /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 0000000..b4b6876
--- /dev/null
+++ b/src/testlib/3rdparty/cycle_p.h
@@ -0,0 +1,494 @@
+/*
+ * 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 _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
+
+#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
+
+#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 0000000..6380a9f
--- /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 0000000..e5d5d59
--- /dev/null
+++ b/src/testlib/qabstracttestlogger.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qabstracttestlogger_p.h"
+#include "QtTest/private/qtestlog_p.h"
+#include "QtTest/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;
+}
+
+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);
+ QTest::stream = 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h
new file mode 100644
index 0000000..298fbad
--- /dev/null
+++ b/src/testlib/qabstracttestlogger_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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;
+
+ static void outputString(const char *msg);
+ static bool isTtyOutput();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qasciikey.cpp b/src/testlib/qasciikey.cpp
new file mode 100644
index 0000000..c02a8ad
--- /dev/null
+++ b/src/testlib/qasciikey.cpp
@@ -0,0 +1,505 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 0000000..7687fec
--- /dev/null
+++ b/src/testlib/qbenchmark.cpp
@@ -0,0 +1,281 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/qbenchmark.h"
+#include "QtTest/private/qbenchmark_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), iterationCount(-1)
+{
+
+}
+
+QBenchmarkTestMethodData::~QBenchmarkTestMethodData()
+{
+ QBenchmarkTestMethodData::current = 0;
+}
+
+void QBenchmarkTestMethodData::beginDataRun()
+{
+ iterationCount = adjustIterationCount(1);
+}
+
+void QBenchmarkTestMethodData::endDataRun()
+{
+
+}
+
+int QBenchmarkTestMethodData::adjustIterationCount(int suggestion)
+{
+ // Let the -iteration-count 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(qint64 value)
+{
+ bool accepted = false;
+
+ // Always accept the result if the iteration count has been
+ // specified on the command line with -iteartion-count.
+ if (QBenchmarkGlobalData::current->iterationCount != -1)
+ accepted = true;
+
+ // Test the result directly without calling the measurer if the minimum time
+ // has been specifed 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);
+}
+
+/*! \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.
+*/
+QTest::QBenchmarkIterationController::QBenchmarkIterationController()
+{
+ QTest::beginBenchmarkMeasurement();
+ i = 0;
+}
+/*! \internal
+*/
+QTest::QBenchmarkIterationController::~QBenchmarkIterationController()
+{
+ QBenchmarkTestMethodData::current->setResult(QTest::endBenchmarkMeasurement());
+}
+
+/*! \internal
+*/
+bool QTest::QBenchmarkIterationController::isDone()
+{
+ 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
+*/
+qint64 QTest::endBenchmarkMeasurement()
+{
+ // the clock is ticking before the line below, don't add code here.
+ return QBenchmarkGlobalData::current->measurer->stop();
+}
+
+/*! \internal
+*/
+void QTest::setResult(qint64 result)
+{
+ QBenchmarkTestMethodData::current->setResult(result);
+}
+
+/*! \internal
+*/
+void QTest::setResult(const QString &tag, qint64 result)
+{
+ QBenchmarkContext context = QBenchmarkGlobalData::current->context;
+ context.tag = tag;
+ QBenchmarkTestMethodData::current->result =
+ QBenchmarkResult( context, result,
+ QBenchmarkTestMethodData::current->iterationCount);
+}
+
+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 0000000..e2b0a74
--- /dev/null
+++ b/src/testlib/qbenchmark.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARK_H
+#define QBENCHMARK_H
+
+#include <QtTest/qtest_global.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:
+ QBenchmarkIterationController();
+ ~QBenchmarkIterationController();
+ bool isDone();
+ void next();
+ int i;
+};
+
+}
+
+#define QBENCHMARK \
+ for (QTest::QBenchmarkIterationController __iteration_controller; __iteration_controller.isDone() == false; __iteration_controller.next())
+
+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 0000000..8bb6e84
--- /dev/null
+++ b/src/testlib/qbenchmark_p.h
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBENCHMARK_P_H
+#define QBENCHMARK_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/qglobal.h>
+
+#if defined(Q_OS_LINUX) && !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"
+
+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(QLatin1String("%1,%2,%3")).arg(slotName).arg(tag).arg(checkpointIndex);
+ return s;
+ }
+
+ QBenchmarkContext() : checkpointIndex(-1) {}
+};
+
+class QBenchmarkResult
+{
+public:
+ QBenchmarkContext context;
+ qint64 value;
+ int iterations;
+ bool valid;
+
+ QBenchmarkResult()
+ : value(-1)
+ , iterations(-1)
+ , valid(false)
+ { }
+
+ QBenchmarkResult(const QBenchmarkContext &context, const qint64 value, const int iterations)
+ : context(context)
+ , value(value)
+ , iterations(iterations)
+ , 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 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 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(qint64 value);
+
+ QBenchmarkResult result;
+ bool resultAccepted;
+ 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 qint64 endBenchmarkMeasurement();
+
+ void setResult(qint64 result);
+ void setResult(const QString &tag, qint64 result);
+}
+
+QT_END_NAMESPACE
+
+#endif // QBENCHMARK_H
diff --git a/src/testlib/qbenchmarkevent.cpp b/src/testlib/qbenchmarkevent.cpp
new file mode 100644
index 0000000..fdd81ff2
--- /dev/null
+++ b/src/testlib/qbenchmarkevent.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qbenchmarkevent_p.h"
+#include "QtTest/private/qbenchmark_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;
+}
+
+QString QBenchmarkEvent::unitText()
+{
+ return QLatin1String("events");
+}
+
+QString QBenchmarkEvent::metricText()
+{
+ return QLatin1String("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 0000000..e027163
--- /dev/null
+++ b/src/testlib/qbenchmarkevent_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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; }
+ QString unitText();
+ QString metricText();
+ 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 0000000..9307450
--- /dev/null
+++ b/src/testlib/qbenchmarkmeasurement.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtTest/private/qbenchmarkmeasurement_p.h"
+#include "QtTest/private/qbenchmark_p.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 > 20);
+}
+
+int QBenchmarkTimeMeasurer::adjustIterationCount(int suggestion)
+{
+ return suggestion;
+}
+
+int QBenchmarkTimeMeasurer::adjustMedianCount(int)
+{
+ return 1;
+}
+
+QString QBenchmarkTimeMeasurer::unitText()
+{
+ return QLatin1String("msec");
+}
+
+QString QBenchmarkTimeMeasurer::metricText()
+{
+ return QLatin1String("walltime");
+}
+
+#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;
+}
+
+QString QBenchmarkTickMeasurer::unitText()
+{
+ return QLatin1String("ticks");
+}
+
+QString QBenchmarkTickMeasurer::metricText()
+{
+ return QLatin1String("cputicks");
+}
+
+#endif
+
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qbenchmarkmeasurement_p.h b/src/testlib/qbenchmarkmeasurement_p.h
new file mode 100644
index 0000000..693a315
--- /dev/null
+++ b/src/testlib/qbenchmarkmeasurement_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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/qdatetime.h>
+#include "3rdparty/cycle_p.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 QString unitText() = 0;
+ virtual QString metricText() = 0;
+};
+
+class QBenchmarkTimeMeasurer : public QBenchmarkMeasurerBase
+{
+public:
+ void start();
+ qint64 checkpoint();
+ qint64 stop();
+ bool isMeasurementAccepted(qint64 measurement);
+ int adjustIterationCount(int sugestion);
+ int adjustMedianCount(int suggestion);
+ QString unitText();
+ QString metricText();
+private:
+ QTime 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();
+ QString unitText();
+ QString metricText();
+private:
+ CycleCounterTicks startTicks;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QBENCHMARK_MEASUREMENT_P_H
diff --git a/src/testlib/qbenchmarkvalgrind.cpp b/src/testlib/qbenchmarkvalgrind.cpp
new file mode 100644
index 0000000..4b4ccd7
--- /dev/null
+++ b/src/testlib/qbenchmarkvalgrind.cpp
@@ -0,0 +1,275 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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"
+
+// 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.numCaptures() == 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(QLatin1String("%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(QLatin1String("%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
+ << QString(QLatin1String("%1")).arg(base) // overall summary
+ << QString(QLatin1String("%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(QLatin1String("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;
+}
+
+QString QBenchmarkCallgrindMeasurer::unitText()
+{
+ return QLatin1String("instr. loads");
+}
+
+QString QBenchmarkCallgrindMeasurer::metricText()
+{
+ return QLatin1String("callgrind");
+}
+
+#endif // QTESTLIB_USE_VALGRIND
diff --git a/src/testlib/qbenchmarkvalgrind_p.h b/src/testlib/qbenchmarkvalgrind_p.h
new file mode 100644
index 0000000..39dc77e
--- /dev/null
+++ b/src/testlib/qbenchmarkvalgrind_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 <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();
+ QString unitText();
+ QString metricText();
+};
+
+QT_END_NAMESPACE
+
+#endif // QBENCHMARKVALGRIND_H
diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp
new file mode 100644
index 0000000..6f10d72
--- /dev/null
+++ b/src/testlib/qplaintestlogger.cpp
@@ -0,0 +1,439 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef Q_OS_WIN
+#include "windows.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)
+ {
+ static bool colored = (!qgetenv("QTEST_COLORED").isEmpty());
+ 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)
+ int length = strlen(str);
+ for (int pos = 0; pos < length; pos +=255) {
+ QString uniText = QString::fromLatin1(str + pos, 255);
+ OutputDebugStringW((const LPCWSTR) uniText.utf16());
+ }
+ if (QTestLog::outputFileName())
+#elif defined(Q_OS_WIN)
+ EnterCriticalSection(&outputCriticalSection);
+ // OutputDebugString is not threadsafe
+ OutputDebugStringA(str);
+ LeaveCriticalSection(&outputCriticalSection);
+#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);
+
+ char buf[1024];
+
+ 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_snprintf(buf, sizeof(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_snprintf(buf, sizeof(buf), "%s: %s::%s(%s%s%s)%s%s\n",
+ type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
+ msg[0] ? " " : "", msg);
+ }
+ memcpy(buf, type, strlen(type));
+ outputMessage(buf);
+ }
+
+ 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 QString(QLatin1String("NAN"));
+ if (number == T(0))
+ return QString(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, "");
+
+
+ QByteArray unitText = QBenchmarkGlobalData::current->measurer->unitText().toAscii();
+
+ qreal valuePerIteration = qreal(result.value) / qreal(result.iterations);
+ char resultBuffer[100] = "";
+ formatResult(resultBuffer, 100, valuePerIteration, countSignificantDigits(result.value));
+
+ QByteArray iterationText = "per iteration";
+
+ char buf2[1024];
+ Q_ASSERT(result.iterations > 0);
+ QTest::qt_snprintf(
+ buf2, sizeof(buf2), "%s %s %s",
+ resultBuffer,
+ unitText.data(),
+ iterationText.data());
+
+ char buf3[1024];
+ Q_ASSERT(result.iterations > 0);
+ QTest::qt_snprintf(
+ buf3, sizeof(buf3), " (total: %s, iterations: %d)\n",
+ QByteArray::number(result.value).constData(), // no 64-bit qt_snprintf support
+ result.iterations);
+
+ char buf[1024];
+ QTest::qt_snprintf(buf, sizeof(buf), "%s%s%s%s%s", buf1, bufTag, fill, buf2, buf3);
+ memcpy(buf, bmtag, strlen(bmtag));
+ outputMessage(buf);
+ }
+}
+
+QPlainTestLogger::QPlainTestLogger()
+{
+#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 {
+ 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);
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qplaintestlogger_p.h b/src/testlib/qplaintestlogger_p.h
new file mode 100644
index 0000000..fac6415
--- /dev/null
+++ b/src/testlib/qplaintestlogger_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qsignaldumper.cpp b/src/testlib/qsignaldumper.cpp
new file mode 100644
index 0000000..0a32a6d
--- /dev/null
+++ b/src/testlib/qsignaldumper.cpp
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 0000000..8d8bbc9
--- /dev/null
+++ b/src/testlib/qsignaldumper_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 0000000..d37bd6f
--- /dev/null
+++ b/src/testlib/qsignalspy.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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/qtest.h b/src/testlib/qtest.h
new file mode 100644
index 0000000..6ea38f7
--- /dev/null
+++ b/src/testlib/qtest.h
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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/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())
+ : qstrdup("Invalid QTime");
+}
+
+template<> inline char *toString(const QDate &date)
+{
+ return date.isValid()
+ ? qstrdup(date.toString(QLatin1String("yyyy/MM/dd")).toLatin1())
+ : 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())
+ : 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());
+}
+
+#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>
+
+#define QTEST_MAIN(TestObject) \
+int main(int argc, char *argv[]) \
+{ \
+ QApplication app(argc, argv); \
+ 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 0000000..d6b0655
--- /dev/null
+++ b/src/testlib/qtest_global.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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)
+# 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_MSVC) && _MSC_VER < 1310) || defined (Q_CC_SUN) || defined (Q_CC_XLC) || (defined (Q_CC_GNU) && (__GNUC__ - 0 < 3))
+# 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 0000000..d389f1c
--- /dev/null
+++ b/src/testlib/qtest_gui.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEST_GUI_H
+#define QTEST_GUI_H
+
+#include <QtTest/qtestassert.h>
+#include <QtTest/qtest.h>
+#include <QtTest/qtestevent.h>
+#include <QtTest/qtestmouse.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 0000000..557690b
--- /dev/null
+++ b/src/testlib/qtestaccessible.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 0000000..1425ceb
--- /dev/null
+++ b/src/testlib/qtestassert.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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/qtestcase.cpp b/src/testlib/qtestcase.cpp
new file mode 100644
index 0000000..f17d95d
--- /dev/null
+++ b/src/testlib/qtestcase.cpp
@@ -0,0 +1,1933 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 <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 a QApplication object and
+ the \a TestClass, and executes all tests in the order they were defined.
+ Use this macro to build stand-alone executables.
+
+ Example:
+ \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 11
+
+ \sa QTEST_APPLESS_MAIN(), QTest::qExec()
+*/
+
+/*! \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}
+*/
+
+/*! \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 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()
+*/
+
+namespace QTest
+{
+ static QObject *currentTestObject = 0;
+
+ struct TestFunction {
+ TestFunction():function(0), data(0) {}
+ ~TestFunction() { delete [] data; }
+ int function;
+ char *data;
+ } testFuncs[512];
+
+ /**
+ * Contains the count of test functions that was supplied
+ * on the command line, if any. Hence, if lastTestFuncIdx is
+ * more than zero, those functions should be run instead of
+ * all appearing in the test case.
+ */
+ static int lastTestFuncIdx = -1;
+
+ static int keyDelay = -1;
+ static int mouseDelay = -1;
+ static int eventDelay = -1;
+ static int keyVerbose = -1;
+
+/*! \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';
+
+ char *idx = str;
+ while (*idx) {
+ if (((*idx < 0x20 && *idx != '\n' && *idx != '\t') || *idx > 0x7e))
+ *idx = '?';
+ ++idx;
+ }
+ return res;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+static void qParseArgs(int argc, char *argv[])
+{
+ lastTestFuncIdx = -1;
+
+ const char *testOptions =
+ " options:\n"
+ " -functions : Returns a list of current testfunctions\n"
+ " -xml : Outputs results as XML document\n"
+ " -lightxml : Outputs results as stream of XML tags\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"
+ " -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"
+ "\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"
+#ifndef QT_NO_PROCESS
+// Will be enabled when tools are integrated.
+// " -chart : Runs the chart generator after the test. No output is printed to the console\n"
+#endif
+ "\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) {
+ qPrintTestSlots();
+ exit(0);
+ } 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], "-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]));
+ }
+ } 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], "-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;
+#ifndef QT_NO_PROCESS
+ } else if (strcmp(argv[i], "-chart") == 0) {
+ QBenchmarkGlobalData::current->createChart = true;
+ QTestLog::setLogMode(QTestLog::XML);
+ QTestLog::redirectOutput("results.xml");
+#endif
+ } else if (strcmp(argv[i], "-qws") == 0) {
+ // do nothing
+ } else if (argv[i][0] == '-') {
+ printf("Unknown option: '%s'\n\n%s", argv[i], testOptions);
+ exit(1);
+ } else {
+ 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);
+ }
+ ++QTest::lastTestFuncIdx;
+ QTest::testFuncs[QTest::lastTestFuncIdx].function = idx;
+ QTest::testFuncs[QTest::lastTestFuncIdx].data = data;
+ QTEST_ASSERT(QTest::lastTestFuncIdx < 512);
+ }
+ }
+}
+
+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);
+ QMetaObject::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);
+ QMetaObject::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);
+ QMetaObject::invokeMethod(QTest::currentTestObject, member, Qt::DirectConnection);
+ // 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);
+
+ /* For each entry in the data table, do: */
+ do {
+ if (!data || !qstrcmp(data, table.testData(curDataIndex)->dataTag())) {
+ foundFunction = true;
+ QTestDataSetter s(table.isEmpty() ? 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);
+
+ QTestLog::startLogging();
+
+ QTestResult::setCurrentTestFunction("initTestCase");
+ QTestResult::setCurrentTestLocation(QTestResult::DataFunc);
+ QTestTable::globalTestTable();
+ QMetaObject::invokeMethod(testObject, "initTestCase_data", Qt::DirectConnection);
+
+ if (!QTestResult::skipCurrentTest() && !QTest::currentTestFailed()) {
+ QTestResult::setCurrentTestLocation(QTestResult::InitFunc);
+ QMetaObject::invokeMethod(testObject, "initTestCase");
+
+ // finishedCurrentTestFunction() resets QTestResult::testFailed(), so use a local copy.
+ const bool previousFailed = QTestResult::testFailed();
+ QTestResult::finishedCurrentTestFunction();
+
+ if(!QTestResult::skipCurrentTest() && !previousFailed) {
+
+ if (lastTestFuncIdx >= 0) {
+ for (int i = 0; i <= lastTestFuncIdx; ++i) {
+ if (!qInvokeTestMethod(metaObject->method(testFuncs[i].function).signature(),
+ testFuncs[i].data))
+ break;
+ }
+ } else {
+ int methodCount = metaObject->methodCount();
+ for (int i = 0; i < methodCount; ++i) {
+ QMetaMethod slotMethod = metaObject->method(i);
+ if (!isValidSlot(slotMethod))
+ continue;
+ if (!qInvokeTestMethod(slotMethod.signature()))
+ break;
+ }
+ }
+ }
+
+ QTestResult::setSkipCurrentTest(false);
+ QTestResult::setCurrentTestFunction("cleanupTestCase");
+ QMetaObject::invokeMethod(testObject, "cleanupTestCase");
+ }
+ QTestResult::finishedCurrentTestFunction();
+ QTestResult::setCurrentTestFunction(0);
+ QTestTable::clearGlobalTestTable();
+
+ QTestLog::stopLogging();
+}
+
+} // 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
+
+ QTestResult::reset();
+
+ QTEST_ASSERT(testObject);
+ QTEST_ASSERT(!currentTestObject);
+ currentTestObject = testObject;
+
+ const QMetaObject *metaObject = testObject->metaObject();
+ QTEST_ASSERT(metaObject);
+
+ QTestResult::setCurrentTestObject(metaObject->className());
+ qParseArgs(argc, argv);
+#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
+
+ qInvokeTestMethods(testObject);
+
+#ifdef QTESTLIB_USE_VALGRIND
+ }
+#endif
+
+ #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
+ #ifdef Q_OS_WIN
+ // rethrow exception to make debugging easier
+ throw;
+ #endif
+ return -1;
+ }
+ #endif
+
+ currentTestObject = 0;
+#ifdef QT_MAC_USE_COCOA
+ if (macNeedsActivate) {
+ IOPMAssertionRelease(powerID);
+ }
+#endif
+
+
+#ifndef QT_NO_PROCESS
+ if (QBenchmarkGlobalData::current->createChart) {
+
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#ifdef Q_OS_WIN
+ const char * path = XSTR(QBENCHLIB_BASE) "/tools/generatereport/generatereport.exe";
+#else
+ const char * path = XSTR(QBENCHLIB_BASE) "/tools/generatereport/generatereport";
+#endif
+#undef XSTR
+#undef STR
+
+ if (QFile::exists(QLatin1String(path))) {
+ QProcess p;
+ p.setProcessChannelMode(QProcess::ForwardedChannels);
+ p.start(QLatin1String(path), QStringList() << QLatin1String("results.xml"));
+ p.waitForFinished(-1);
+ } else {
+ qWarning("Could not find %s, please make sure it is compiled.", path);
+ }
+ }
+#endif
+
+#if defined(QTEST_NOEXITCODE) || (defined(QT_BUILD_INTERNAL) && !defined(QTEST_FORCE_EXITCODE))
+ 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 <>
+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 <>
+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 <> 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::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
+*/
+
+/*! \fn int QTest::qt_snprintf(char *str, int size, const char *format, ...)
+ \internal
+*/
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
new file mode 100644
index 0000000..4e5deff
--- /dev/null
+++ b/src/testlib/qtestcase.h
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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_ARCH_WINDOWSCE) && defined(QT_COORD_TYPE)
+ 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)
+ 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 */
+ 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);
+ }
+
+ 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/qtestdata.cpp b/src/testlib/qtestdata.cpp
new file mode 100644
index 0000000..3f766b4
--- /dev/null
+++ b/src/testlib/qtestdata.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 0000000..b673bb9
--- /dev/null
+++ b/src/testlib/qtestdata.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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/qtestevent.h b/src/testlib/qtestevent.h
new file mode 100644
index 0000000..1eefd7b
--- /dev/null
+++ b/src/testlib/qtestevent.h
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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>
+#include <QtTest/qtestkeyboard.h>
+#include <QtTest/qtestmouse.h>
+#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() {}
+};
+
+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;
+};
+
+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(); }
+
+ 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)); }
+
+ 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/qtesteventloop.h b/src/testlib/qtesteventloop.h
new file mode 100644
index 0000000..2a675d2
--- /dev/null
+++ b/src/testlib/qtesteventloop.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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/qtestkeyboard.h b/src/testlib/qtestkeyboard.h
new file mode 100644
index 0000000..68dc53c
--- /dev/null
+++ b/src/testlib/qtestkeyboard.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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/qtestlog.cpp b/src/testlib/qtestlog.cpp
new file mode 100644
index 0000000..aa56e6c
--- /dev/null
+++ b/src/testlib/qtestlog.cpp
@@ -0,0 +1,364 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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>
+
+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 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.");
+ 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;
+ }
+ }
+
+}
+
+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()
+{
+ QTEST_ASSERT(!QTest::testLogger);
+
+ switch (QTest::logMode) {
+ case QTestLog::Plain:
+ QTest::testLogger = new QPlainTestLogger();
+ break;
+ case QTestLog::XML:
+ QTest::testLogger = new QXmlTestLogger(QXmlTestLogger::Complete);
+ break;
+ case QTestLog::LightXML:
+ QTest::testLogger = new QXmlTestLogger(QXmlTestLogger::Light);
+ }
+
+ 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(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;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h
new file mode 100644
index 0000000..fa49a38
--- /dev/null
+++ b/src/testlib/qtestlog_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 QTestLog
+{
+public:
+ enum LogMode { Plain = 0, XML, LightXML };
+
+ 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 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);
+
+private:
+ QTestLog();
+ ~QTestLog();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h
new file mode 100644
index 0000000..48b9a6c
--- /dev/null
+++ b/src/testlib/qtestmouse.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef 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));
+ qApp->processEvents();
+ return;
+ default:
+ QTEST_ASSERT(false);
+ }
+ QSpontaneKeyEvent::setSpontaneous(&me);
+ if (!qApp->notify(widget, &me))
+ QTest::qWarn("Mouse event not accepted by receiving widget");
+
+ }
+
+ 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 0000000..39759b5
--- /dev/null
+++ b/src/testlib/qtestresult.cpp
@@ -0,0 +1,349 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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))
+ return true; // we don't care
+
+ if (QTest::expectFailMode) {
+ 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 0000000..0f1e64b
--- /dev/null
+++ b/src/testlib/qtestresult_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 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 0000000..e125329
--- /dev/null
+++ b/src/testlib/qtestspontaneevent.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 0000000..c1b5fc1
--- /dev/null
+++ b/src/testlib/qtestsystem.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTSYSTEM_H
+#define QTESTSYSTEM_H
+
+#include <QtTest/qtestcase.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+namespace QTest
+{
+ inline static void qWait(int ms)
+ {
+ Q_ASSERT(QCoreApplication::instance());
+
+ QTime timer;
+ timer.start();
+ do {
+ QCoreApplication::processEvents(QEventLoop::AllEvents, ms);
+ QTest::qSleep(10);
+ } while (timer.elapsed() < ms);
+ }
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/testlib/qtesttable.cpp b/src/testlib/qtesttable.cpp
new file mode 100644
index 0000000..7c1cce0
--- /dev/null
+++ b/src/testlib/qtesttable.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 0000000..4b20170
--- /dev/null
+++ b/src/testlib/qtesttable_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTTABLE_P_H
+#define QTESTTABLE_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 QTestData;
+class QTestTablePrivate;
+
+class QTestTable
+{
+public:
+ QTestTable();
+ ~QTestTable();
+
+ void addColumn(int elementType, const char *elementName);
+ QTestData *newData(const char *tag);
+
+ int elementCount() const;
+ int dataCount() const;
+
+ int elementTypeId(int index) const;
+ const char *dataTag(int index) const;
+ int indexOf(const char *elementName) const;
+ bool isEmpty() const;
+ QTestData *testData(int index) const;
+
+ static QTestTable *globalTestTable();
+ static QTestTable *currentTestTable();
+ static void clearGlobalTestTable();
+
+private:
+ Q_DISABLE_COPY(QTestTable)
+
+ QTestTablePrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/qxmltestlogger.cpp b/src/testlib/qxmltestlogger.cpp
new file mode 100644
index 0000000..bba98da
--- /dev/null
+++ b/src/testlib/qxmltestlogger.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <QtCore/qglobal.h>
+
+#include "QtTest/private/qxmltestlogger_p.h"
+#include "QtTest/private/qtestresult_p.h"
+#include "QtTest/private/qbenchmark_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest {
+
+ static const char* xmlMessageType2String(QAbstractTestLogger::MessageTypes type)
+ {
+ switch (type) {
+ case QAbstractTestLogger::Warn:
+ return "warn";
+ case QAbstractTestLogger::QSystem:
+ return "system";
+ case QAbstractTestLogger::QDebug:
+ return "qdebug";
+ case QAbstractTestLogger::QWarning:
+ return "qwarn";
+ case QAbstractTestLogger::QFatal:
+ return "qfatal";
+ case QAbstractTestLogger::Skip:
+ return "skip";
+ case QAbstractTestLogger::Info:
+ return "info";
+ }
+ return "??????";
+ }
+
+ static const char* xmlIncidentType2String(QAbstractTestLogger::IncidentTypes type)
+ {
+ switch (type) {
+ case QAbstractTestLogger::Pass:
+ return "pass";
+ case QAbstractTestLogger::XFail:
+ return "xfail";
+ case QAbstractTestLogger::Fail:
+ return "fail";
+ case QAbstractTestLogger::XPass:
+ return "xpass";
+ }
+ return "??????";
+ }
+
+}
+
+
+QXmlTestLogger::QXmlTestLogger(XmlMode mode ):
+ xmlmode(mode)
+{
+
+}
+
+QXmlTestLogger::~QXmlTestLogger()
+{
+
+}
+
+
+void QXmlTestLogger::startLogging()
+{
+ QAbstractTestLogger::startLogging();
+ char buf[1024];
+
+ if (xmlmode == QXmlTestLogger::Complete) {
+ QTest::qt_snprintf(buf, sizeof(buf),
+ "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+ "<TestCase name=\"%s\">\n", QTestResult::currentTestObjectName());
+ outputString(buf);
+ }
+
+ QTest::qt_snprintf(buf, sizeof(buf),
+ "<Environment>\n"
+ " <QtVersion>%s</QtVersion>\n"
+ " <QTestVersion>"QTEST_VERSION_STR"</QTestVersion>\n"
+ "</Environment>\n", qVersion());
+ outputString(buf);
+}
+
+void QXmlTestLogger::stopLogging()
+{
+ if (xmlmode == QXmlTestLogger::Complete) {
+ outputString("</TestCase>\n");
+ }
+
+ QAbstractTestLogger::stopLogging();
+}
+
+void QXmlTestLogger::enterTestFunction(const char *function)
+{
+ char buf[1024];
+ QTest::qt_snprintf(buf, sizeof(buf), "<TestFunction name=\"%s\">\n", function);
+ outputString(buf);
+}
+
+void QXmlTestLogger::leaveTestFunction()
+{
+ outputString("</TestFunction>\n");
+}
+
+namespace QTest
+{
+
+inline static bool isEmpty(const char *str)
+{
+ return !str || !str[0];
+}
+
+static const char *incidentFormatString(bool noDescription, bool noTag)
+{
+ if (noDescription) {
+ if (noTag)
+ return "<Incident type=\"%s\" file=\"%s\" line=\"%d\" />\n";
+ else
+ return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
+ "</Incident>\n";
+ } else {
+ if (noTag)
+ return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <Description><![CDATA[%s%s%s%s]]></Description>\n"
+ "</Incident>\n";
+ else
+ return "<Incident type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
+ " <Description><![CDATA[%s]]></Description>\n"
+ "</Incident>\n";
+ }
+}
+
+static const char *benchmarkResultFormatString()
+{
+ return "<BenchmarkResult metric=\"%s\" tag=\"%s\" value=\"%s\" iterations=\"%d\" />\n";
+}
+
+static const char *messageFormatString(bool noDescription, bool noTag)
+{
+ if (noDescription) {
+ if (noTag)
+ return "<Message type=\"%s\" file=\"%s\" line=\"%d\" />\n";
+ else
+ return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <DataTag><![CDATA[%s%s%s%s]]></DataTag>\n"
+ "</Message>\n";
+ } else {
+ if (noTag)
+ return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <Description><![CDATA[%s%s%s%s]]></Description>\n"
+ "</Message>\n";
+ else
+ return "<Message type=\"%s\" file=\"%s\" line=\"%d\">\n"
+ " <DataTag><![CDATA[%s%s%s]]></DataTag>\n"
+ " <Description><![CDATA[%s]]></Description>\n"
+ "</Message>\n";
+ }
+}
+
+} // namespace
+
+void QXmlTestLogger::addIncident(IncidentTypes type, const char *description,
+ const char *file, int line)
+{
+ char buf[1536];
+ const char *tag = QTestResult::currentDataTag();
+ const char *gtag = QTestResult::currentGlobalDataTag();
+ const char *filler = (tag && gtag) ? ":" : "";
+ const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
+
+ QTest::qt_snprintf(buf, sizeof(buf),
+ QTest::incidentFormatString(QTest::isEmpty(description), notag),
+ QTest::xmlIncidentType2String(type),
+ file ? file : "", line,
+ gtag ? gtag : "",
+ filler,
+ tag ? tag : "",
+ description ? description : "");
+
+ outputString(buf);
+}
+
+void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
+{
+ char buf[1536];
+ QTest::qt_snprintf(
+ buf, sizeof(buf),
+ QTest::benchmarkResultFormatString(),
+ QBenchmarkGlobalData::current->measurer->metricText().toAscii().data(),
+ result.context.tag.toAscii().data(),
+ QByteArray::number(result.value).constData(), //no 64-bit qt_snprintf support
+ result.iterations);
+ outputString(buf);
+}
+
+void QXmlTestLogger::addMessage(MessageTypes type, const char *message,
+ const char *file, int line)
+{
+ char buf[1536];
+ char msgbuf[1024];
+ const char *tag = QTestResult::currentDataTag();
+ const char *gtag = QTestResult::currentGlobalDataTag();
+ const char *filler = (tag && gtag) ? ":" : "";
+ const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
+
+ QTest::qt_snprintf(msgbuf, sizeof(msgbuf), "%s",
+ message ? message : "");
+
+ QTest::qt_snprintf(buf, sizeof(buf),
+ QTest::messageFormatString(QTest::isEmpty(message), notag),
+ QTest::xmlMessageType2String(type),
+ file ? file : "", line,
+ gtag ? gtag : "",
+ filler,
+ tag ? tag : "",
+ msgbuf);
+
+ outputString(buf);
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qxmltestlogger_p.h b/src/testlib/qxmltestlogger_p.h
new file mode 100644
index 0000000..3e78969
--- /dev/null
+++ b/src/testlib/qxmltestlogger_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXMLTESTLOGGER_P_H
+#define QXMLTESTLOGGER_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 QXmlTestLogger : public QAbstractTestLogger
+{
+public:
+ enum XmlMode { Complete = 0, Light };
+
+ QXmlTestLogger(XmlMode mode = Complete);
+ ~QXmlTestLogger();
+
+ 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);
+
+private:
+ XmlMode xmlmode;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro
new file mode 100644
index 0000000..90bd92d
--- /dev/null
+++ b/src/testlib/testlib.pro
@@ -0,0 +1,27 @@
+TARGET = QtTest
+QPRO_PWD = $$PWD
+QT = core
+INCLUDEPATH += .
+
+unix:!embedded {
+ QMAKE_PKGCONFIG_DESCRIPTION = Qt Unit Testing Library
+ QMAKE_PKGCONFIG_REQUIRES = QtCore
+}
+
+# Input
+HEADERS = qtest_global.h qtestcase.h qtestdata.h qtesteventloop.h
+SOURCES = qtestcase.cpp qtestlog.cpp qtesttable.cpp qtestdata.cpp qtestresult.cpp qasciikey.cpp qplaintestlogger.cpp qxmltestlogger.cpp qsignaldumper.cpp qabstracttestlogger.cpp qbenchmark.cpp qbenchmarkmeasurement.cpp qbenchmarkvalgrind.cpp qbenchmarkevent.cpp
+
+DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII QTESTLIB_MAKEDLL QT_NO_DATASTREAM
+
+wince*:{
+ LIBS += libcmt.lib corelibc.lib ole32.lib oleaut32.lib uuid.lib commctrl.lib coredll.lib winsock.lib
+}
+
+mac {
+ LIBS += -framework IOKit -framework Security
+}
+
+include(../qbase.pri)
+QMAKE_TARGET_PRODUCT = QTestLib
+QMAKE_TARGET_DESCRIPTION = Qt Unit Testing Library