Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2020
- 80 participants
- 745 discussions
10 Feb '20
Signed-off-by: Alex Henrie <alexhenrie24(a)gmail.com>
---
dlls/iphlpapi/tests/iphlpapi.c | 42 ++++++++++++++--------------------
1 file changed, 17 insertions(+), 25 deletions(-)
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c
index 1b0bc9383a..a1fdf2716b 100644
--- a/dlls/iphlpapi/tests/iphlpapi.c
+++ b/dlls/iphlpapi/tests/iphlpapi.c
@@ -169,28 +169,25 @@ static void freeIPHlpApi(void)
/* replacement for inet_ntoa */
static const char *ntoa( DWORD ip )
{
- static char buffer[40];
+ static char buffers[4][16];
+ static int i = -1;
ip = htonl(ip);
- sprintf( buffer, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff );
- return buffer;
+ i = (i + 1) % ARRAY_SIZE(buffers);
+ sprintf( buffers[i], "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff );
+ return buffers[i];
}
static const char *ntoa6( IN6_ADDR *ip )
{
- static char buffer[40];
- char *buf = buffer;
+ static char buffers[4][40];
+ static int i = -1;
unsigned short *p = ip->u.Word;
- unsigned int i = 0;
- while (i < 8)
- {
- if (i > 0)
- *buf++ = ':';
- buf += sprintf( buf, "%x", htons(p[i]) );
- i++;
- }
- return buffer;
+ i = (i + 1) % ARRAY_SIZE(buffers);
+ sprintf( buffers[i], "%x:%x:%x:%x:%x:%x:%x:%x",
+ htons(p[0]), htons(p[1]), htons(p[2]), htons(p[3]), htons(p[4]), htons(p[5]), htons(p[6]), htons(p[7]) );
+ return buffers[i];
}
/*
@@ -382,8 +379,6 @@ static void testGetIpForwardTable(void)
trace( "IP forward table: %u entries\n", buf->dwNumEntries );
for (i = 0; i < buf->dwNumEntries; i++)
{
- char buffer[100];
-
if (!U1(buf->table[i]).dwForwardDest) /* Default route */
{
todo_wine
@@ -403,9 +398,8 @@ todo_wine
* value so it is not worth testing in this case. */
}
- sprintf( buffer, "dest %s", ntoa( buf->table[i].dwForwardDest ));
- sprintf( buffer + strlen(buffer), " mask %s", ntoa( buf->table[i].dwForwardMask ));
- trace( "%u: %s gw %s if %u type %u proto %u\n", i, buffer,
+ trace( "%u: dest %s mask %s gw %s if %u type %u proto %u\n", i,
+ ntoa( buf->table[i].dwForwardDest ), ntoa( buf->table[i].dwForwardMask ),
ntoa( buf->table[i].dwForwardNextHop ), buf->table[i].dwForwardIfIndex,
U1(buf->table[i]).dwForwardType, U1(buf->table[i]).dwForwardProto );
}
@@ -890,12 +884,10 @@ static void testGetTcpTable(void)
trace( "TCP table: %u entries\n", buf->dwNumEntries );
for (i = 0; i < buf->dwNumEntries; i++)
{
- char buffer[40];
- sprintf( buffer, "local %s:%u",
- ntoa(buf->table[i].dwLocalAddr), ntohs(buf->table[i].dwLocalPort) );
- trace( "%u: %s remote %s:%u state %u\n",
- i, buffer, ntoa( buf->table[i].dwRemoteAddr ),
- ntohs(buf->table[i].dwRemotePort), U(buf->table[i]).dwState );
+ trace( "%u: local %s:%u remote %s:%u state %u\n", i,
+ ntoa(buf->table[i].dwLocalAddr), ntohs(buf->table[i].dwLocalPort),
+ ntoa(buf->table[i].dwRemoteAddr), ntohs(buf->table[i].dwRemotePort),
+ U(buf->table[i]).dwState );
}
}
HeapFree(GetProcessHeap(), 0, buf);
--
2.25.0
1
0
Signed-off-by: Alistair Leslie-Hughes <leslie_alistair(a)hotmail.com>
---
configure | 2 +
configure.ac | 1 +
dlls/directmanipulation/Makefile.in | 8 +++
dlls/directmanipulation/directmanip.idl | 38 +++++++++++
dlls/directmanipulation/directmanipulation.c | 67 +++++++++++++++++++
.../directmanipulation.spec | 6 ++
6 files changed, 122 insertions(+)
create mode 100644 dlls/directmanipulation/Makefile.in
create mode 100644 dlls/directmanipulation/directmanip.idl
create mode 100644 dlls/directmanipulation/directmanipulation.c
create mode 100644 dlls/directmanipulation/directmanipulation.spec
diff --git a/configure b/configure
index 7ff3737bda..764646610d 100755
--- a/configure
+++ b/configure
@@ -1239,6 +1239,7 @@ enable_dhtmled_ocx
enable_difxapi
enable_dinput
enable_dinput8
+enable_directmanipulation
enable_dispex
enable_dmband
enable_dmcompos
@@ -20359,6 +20360,7 @@ wine_fn_config_makefile dlls/dinput enable_dinput
wine_fn_config_makefile dlls/dinput/tests enable_tests
wine_fn_config_makefile dlls/dinput8 enable_dinput8
wine_fn_config_makefile dlls/dinput8/tests enable_tests
+wine_fn_config_makefile dlls/directmanipulation enable_directmanipulation
wine_fn_config_makefile dlls/dispdib.dll16 enable_win16
wine_fn_config_makefile dlls/dispex enable_dispex
wine_fn_config_makefile dlls/dispex/tests enable_tests
diff --git a/configure.ac b/configure.ac
index 681d315eed..926d9e65d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3169,6 +3169,7 @@ WINE_CONFIG_MAKEFILE(dlls/dinput)
WINE_CONFIG_MAKEFILE(dlls/dinput/tests)
WINE_CONFIG_MAKEFILE(dlls/dinput8)
WINE_CONFIG_MAKEFILE(dlls/dinput8/tests)
+WINE_CONFIG_MAKEFILE(dlls/directmanipulation)
WINE_CONFIG_MAKEFILE(dlls/dispdib.dll16,enable_win16)
WINE_CONFIG_MAKEFILE(dlls/dispex)
WINE_CONFIG_MAKEFILE(dlls/dispex/tests)
diff --git a/dlls/directmanipulation/Makefile.in b/dlls/directmanipulation/Makefile.in
new file mode 100644
index 0000000000..331c2a8420
--- /dev/null
+++ b/dlls/directmanipulation/Makefile.in
@@ -0,0 +1,8 @@
+MODULE = directmanipulation.dll
+
+EXTRADLLFLAGS = -mno-cygwin
+
+IDL_SRCS = directmanip.idl
+
+C_SRCS = \
+ directmanipulation.c
diff --git a/dlls/directmanipulation/directmanip.idl b/dlls/directmanipulation/directmanip.idl
new file mode 100644
index 0000000000..ff00668ba5
--- /dev/null
+++ b/dlls/directmanipulation/directmanip.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 Alistair Leslie-Hughes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#pragma makedep register
+
+[
+ uuid(54e211b6-3650-4f75-8334-fa359598e1c5),
+ threading(both)
+]
+coclass DirectManipulationManager
+{
+ interface IDirectManipulationManager2;
+ [default] interface IDirectManipulationManager;
+}
+
+[
+ uuid(99793286-77cc-4b57-96db-3b354f6f9fb5),
+ threading(both)
+]
+coclass DirectManipulationSharedManager
+{
+ interface IDirectManipulationManager2;
+ [default] interface IDirectManipulationManager;
+}
diff --git a/dlls/directmanipulation/directmanipulation.c b/dlls/directmanipulation/directmanipulation.c
new file mode 100644
index 0000000000..136b2976a4
--- /dev/null
+++ b/dlls/directmanipulation/directmanipulation.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 Alistair Leslie-Hughes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "oleidl.h"
+#include "rpcproxy.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(manipulation);
+
+static HINSTANCE dm_instance;
+
+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
+{
+ TRACE("(%p, %u, %p)\n", instance, reason, reserved);
+
+ switch (reason)
+ {
+ case DLL_WINE_PREATTACH:
+ return FALSE; /* prefer native version */
+ case DLL_PROCESS_ATTACH:
+ dm_instance = instance;
+ DisableThreadLibraryCalls(instance);
+ break;
+ }
+
+ return TRUE;
+}
+
+HRESULT WINAPI DllRegisterServer(void)
+{
+ return __wine_register_resources( dm_instance );
+}
+
+HRESULT WINAPI DllUnregisterServer(void)
+{
+ return __wine_unregister_resources( dm_instance );
+}
+
+HRESULT WINAPI DllCanUnloadNow(void)
+{
+ return S_FALSE;
+}
+
+HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
\ No newline at end of file
diff --git a/dlls/directmanipulation/directmanipulation.spec b/dlls/directmanipulation/directmanipulation.spec
new file mode 100644
index 0000000000..3f0004daeb
--- /dev/null
+++ b/dlls/directmanipulation/directmanipulation.spec
@@ -0,0 +1,6 @@
+@ stub InitializeDManipHook
+@ stdcall -private DllCanUnloadNow()
+@ stub DllGetActivationFactory
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
--
2.17.1
2
1
10 Feb '20
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/sysparams.c | 16 ++++++----------
dlls/user32/tests/monitor.c | 4 ++--
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c
index 0a0a2c70bd..a146f31071 100644
--- a/dlls/user32/sysparams.c
+++ b/dlls/user32/sysparams.c
@@ -3285,18 +3285,14 @@ LONG WINAPI ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, HWND
{
trace_devmode(devmode);
- /* This is the minimal dmSize that XP accepts */
- if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmFields))
- return DISP_CHANGE_FAILED;
+ if (devmode->dmSize < FIELD_OFFSET(DEVMODEW, dmICMMethod))
+ return DISP_CHANGE_BADMODE;
- if (devmode->dmSize >= FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(devmode->dmFields))
- {
- if (((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
- ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
- ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
- ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
+ if (((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel) ||
+ ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth) ||
+ ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight) ||
+ ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency))
def_mode = FALSE;
- }
}
if (def_mode)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 03fd6f3ec3..e669b2b82e 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -401,11 +401,11 @@ static void test_ChangeDisplaySettingsEx(void)
dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod) - 1;
res = ChangeDisplaySettingsW(&dmW, CDS_TEST);
- todo_wine ok(res == DISP_CHANGE_BADMODE, "ChangeDisplaySettingsW returned %d, expect DISP_CHANGE_BADMODE\n", res);
+ ok(res == DISP_CHANGE_BADMODE, "ChangeDisplaySettingsW returned %d, expect DISP_CHANGE_BADMODE\n", res);
dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod) - 1;
res = ChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL);
- todo_wine ok(res == DISP_CHANGE_BADMODE, "ChangeDisplaySettingsExW returned %d, expect DISP_CHANGE_BADMODE\n", res);
+ ok(res == DISP_CHANGE_BADMODE, "ChangeDisplaySettingsExW returned %d, expect DISP_CHANGE_BADMODE\n", res);
dmW.dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
res = ChangeDisplaySettingsW(&dmW, CDS_TEST);
--
2.20.1
1
0
10 Feb '20
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/sysparams.c | 5 ++++-
include/winuser.h | 20 +++++++++++---------
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c
index 2523df6bf2..0a0a2c70bd 100644
--- a/dlls/user32/sysparams.c
+++ b/dlls/user32/sysparams.c
@@ -3218,8 +3218,11 @@ static const CHAR *_CDS_flags(DWORD fields)
_X_FIELD(CDS, FULLSCREEN)
_X_FIELD(CDS, GLOBAL)
_X_FIELD(CDS, SET_PRIMARY)
+ _X_FIELD(CDS, VIDEOPARAMETERS)
+ _X_FIELD(CDS, ENABLE_UNSAFE_MODES)
+ _X_FIELD(CDS, DISABLE_UNSAFE_MODES)
_X_FIELD(CDS, RESET)
- _X_FIELD(CDS, SETRECT)
+ _X_FIELD(CDS, RESET_EX)
_X_FIELD(CDS, NORESET)
*p = 0;
diff --git a/include/winuser.h b/include/winuser.h
index 51c73d25c2..718f6e1c54 100644
--- a/include/winuser.h
+++ b/include/winuser.h
@@ -1501,15 +1501,17 @@ DECL_WINELIB_TYPE_AW(LPHELPWININFO)
#define DISP_CHANGE_BADDUALVIEW (-6)
/* ChangeDisplaySettings.dwFlags */
-#define CDS_UPDATEREGISTRY 0x00000001
-#define CDS_TEST 0x00000002
-#define CDS_FULLSCREEN 0x00000004
-#define CDS_GLOBAL 0x00000008
-#define CDS_SET_PRIMARY 0x00000010
-#define CDS_VIDEOPARAMETERS 0x00000020
-#define CDS_NORESET 0x10000000
-#define CDS_SETRECT 0x20000000
-#define CDS_RESET 0x40000000
+#define CDS_UPDATEREGISTRY 0x00000001
+#define CDS_TEST 0x00000002
+#define CDS_FULLSCREEN 0x00000004
+#define CDS_GLOBAL 0x00000008
+#define CDS_SET_PRIMARY 0x00000010
+#define CDS_VIDEOPARAMETERS 0x00000020
+#define CDS_ENABLE_UNSAFE_MODES 0x00000100
+#define CDS_DISABLE_UNSAFE_MODES 0x00000200
+#define CDS_NORESET 0x10000000
+#define CDS_RESET_EX 0x20000000
+#define CDS_RESET 0x40000000
typedef struct tagWNDCLASSEXA
{
--
2.20.1
1
0
Hey all,
There seem to be some new failures on some Windows 7 machines since last
weekend when the website was really slow:
https://test.winehq.org/data/tests/urlmon:protocol.html
https://test.winehq.org/data/tests/urlmon:url.html
https://test.winehq.org/data/tests/winhttp:winhttp.html
https://test.winehq.org/data/tests/wininet:http.html
I'm not sure if something got changed on the server side or if something
else is going on.
Cheers,
Sven
2
1
[PATCH] tests: Limit spam from todos, skips and traces when winetest_debug==1.
by Francois Gouget 09 Feb '20
by Francois Gouget 09 Feb '20
09 Feb '20
Some tests loop on system resources like fonts and issue todos, skips or
even traces on every iteration. Depending on the machine configuration
this can result in a lot of traces and push WineTest reports above the
1.5 MB limit.
So on low debugging levels automatically silence test lines that issue
more than 50 such messages. A count of the silenced messages is given at
the end.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
Nobody objected so I'll take that as meaning everyone thinks this is a
good idea. So now in patch form...
https://www.winehq.org/pipermail/wine-devel/2020-February/158784.html
I reduced the winetest_mute_threshold a little bit.
include/wine/test.h | 77 ++++++++++++++++++++++++++++++++++++---------
1 file changed, 63 insertions(+), 14 deletions(-)
diff --git a/include/wine/test.h b/include/wine/test.h
index 5c3b432a9a2..edaf89bcca9 100644
--- a/include/wine/test.h
+++ b/include/wine/test.h
@@ -62,6 +62,9 @@ extern int winetest_interactive;
/* report successful tests (BOOL) */
extern int winetest_report_success;
+/* silence todos and skips above this threshold */
+extern int winetest_mute_threshold;
+
/* current platform */
extern const char *winetest_platform;
@@ -211,6 +214,9 @@ const char *winetest_platform = "windows";
/* report successful tests (BOOL) */
int winetest_report_success = 0;
+/* silence todos and skips above this threshold */
+int winetest_mute_threshold = 42;
+
/* passing arguments around */
static int winetest_argc;
static char** winetest_argv;
@@ -222,6 +228,12 @@ static LONG failures; /* number of failures */
static LONG skipped; /* number of skipped test chunks */
static LONG todo_successes; /* number of successful tests inside todo block */
static LONG todo_failures; /* number of failures inside todo block */
+static LONG muted_traces; /* number of silenced traces */
+static LONG muted_skipped; /* same as skipped but silent */
+static LONG muted_todo_successes; /* same as todo_successes but silent */
+
+/* counts how many times a given line printed a message */
+static LONG line_counters[16384];
/* The following data must be kept track of on a per-thread basis */
struct tls_data
@@ -284,6 +296,25 @@ int broken( int condition )
return (strcmp(winetest_platform, "windows") == 0) && condition;
}
+static LONG winetest_add_line( void )
+{
+ struct tls_data *data;
+ int index, count;
+
+ if (winetest_debug > 1)
+ return 0;
+
+ data = get_tls_data();
+ index = data->current_line % ARRAY_SIZE(line_counters);
+ count = InterlockedIncrement(line_counters + index) - 1;
+ if (count == winetest_mute_threshold)
+ printf( "%s:%d Line has been silenced after %d occurrences\n",
+ data->current_file, data->current_line,
+ winetest_mute_threshold);
+
+ return count;
+}
+
/*
* Checks condition.
* Parameters:
@@ -310,13 +341,19 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
}
else
{
- if (winetest_debug > 0)
+ if (!winetest_debug ||
+ winetest_add_line() < winetest_mute_threshold)
{
- printf( "%s:%d: Test marked todo: ",
- data->current_file, data->current_line );
- vprintf(msg, args);
+ if (winetest_debug > 0)
+ {
+ printf( "%s:%d Test marked todo: ",
+ data->current_file, data->current_line );
+ vprintf(msg, args);
+ }
+ InterlockedIncrement(&todo_successes);
}
- InterlockedIncrement(&todo_successes);
+ else
+ InterlockedIncrement(&muted_todo_successes);
return 1;
}
}
@@ -353,24 +390,32 @@ void __winetest_cdecl winetest_ok( int condition, const char *msg, ... )
void __winetest_cdecl winetest_trace( const char *msg, ... )
{
__winetest_va_list valist;
- struct tls_data *data = get_tls_data();
- if (winetest_debug > 0)
+ if (!winetest_debug)
+ return;
+ if (winetest_add_line() < winetest_mute_threshold)
{
- printf( "%s:%d: ", data->current_file, data->current_line );
+ struct tls_data *data = get_tls_data();
+ printf( "%s:%d ", data->current_file, data->current_line );
__winetest_va_start(valist, msg);
vprintf(msg, valist);
__winetest_va_end(valist);
}
+ else
+ InterlockedIncrement(&muted_traces);
}
void winetest_vskip( const char *msg, __winetest_va_list args )
{
- struct tls_data *data = get_tls_data();
-
- printf( "%s:%d: Tests skipped: ", data->current_file, data->current_line );
- vprintf(msg, args);
- skipped++;
+ if (winetest_add_line() < winetest_mute_threshold)
+ {
+ struct tls_data *data = get_tls_data();
+ printf( "%s:%d Tests skipped: ", data->current_file, data->current_line );
+ vprintf(msg, args);
+ InterlockedIncrement(&skipped);
+ }
+ else
+ InterlockedIncrement(&muted_skipped);
}
void __winetest_cdecl winetest_skip( const char *msg, ... )
@@ -504,7 +549,11 @@ static int run_test( const char *name )
if (winetest_debug)
{
- printf( "%04x:%s: %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
+ if (muted_todo_successes || muted_skipped || muted_traces)
+ printf( "%04x:%s Silenced %d todos, %d skips and %d traces.\n",
+ GetCurrentProcessId(), test->name,
+ muted_todo_successes, muted_skipped, muted_traces);
+ printf( "%04x:%s %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
GetCurrentProcessId(), test->name,
successes + failures + todo_successes + todo_failures,
todo_successes, failures + todo_failures,
--
2.20.1
1
0
09 Feb '20
Prior to this patch the log files needed to be parsed every time the
error list is needed. Parsing the reference report and diffing its
errors also needs to be repeated every time the list of new errors
is needed. Both of these have a significant impact on the JobDetails
page load time.
So this patch lets the task scripts (WineRun*) extract the log file
errors when they complete, detect the new errors, and saves the result
in a .errors file stored next to the original log file. All that's
needed then is to read the small .errors file to get the full errors
list along with their status (old or new) which speeds up WineSendLog
and JobDetails.
However the task scripts cannot generate the errors cache file for the
testbot.log file because that file is complete only once the task
scripts exits. So the errors cache file for it is generated by the
WineSendLog script once the job completes.
Furthermore the .err files were used to store the validation errors
detected by the ParseWineTestReport() function. These are now stored
as the '.Extra' error group in the .errors files, making the .err files
redundant.
Then instead of showing the content of the xxx and xxx.err file in
succession, the scripts either just iterate over all the error groups,
or present the full content of the log first and then show the 'extra'
error groups, that is those that are not tied to a specific log line
number.
Note: This requires running UpdateTaskLogs to create the new .errors
files and to delete the obsolete .err files.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48035
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
This is the big patch.
As before it would be useful to keep a trace of what UpdateTaskLogs did
in case something went wrong or just to check it worked as expected:
cd testbot/var && ../bin/UpdateTaskLogs --debug 2>&1 | tee UpdateTaskLogs.log
testbot/bin/Janitor.pl | 2 +-
testbot/bin/UpdateTaskLogs | 136 +++++++------
testbot/bin/WineRunBuild.pl | 2 +
testbot/bin/WineRunReconfig.pl | 2 +
testbot/bin/WineRunTask.pl | 17 +-
testbot/bin/WineRunWineTest.pl | 16 +-
testbot/bin/WineSendLog.pl | 111 +++++++----
testbot/lib/WineTestBot/LogUtils.pm | 275 ++++++++++++++++++++++----
testbot/lib/WineTestBot/StepsTasks.pm | 7 -
testbot/lib/WineTestBot/Tasks.pm | 4 +
testbot/web/JobDetails.pl | 91 ++++-----
11 files changed, 445 insertions(+), 218 deletions(-)
diff --git a/testbot/bin/Janitor.pl b/testbot/bin/Janitor.pl
index 888bebf3f2..0635b37880 100755
--- a/testbot/bin/Janitor.pl
+++ b/testbot/bin/Janitor.pl
@@ -315,7 +315,7 @@ if (opendir(my $dh, "$DataDir/latest"))
my $TTL = $JobPurgeDays ? $JobPurgeDays - $Age : undef;
# Keep the regexp in sync with WineTestBot::Task::GetRefReportName()
- if ($Entry =~ /^([a-zA-Z0-9_]+)-job[0-9]+-[a-zA-Z0-9_]+\.report(?:\.err)?$/)
+ if ($Entry =~ /^([a-zA-Z0-9_]+)-job[0-9]+-[a-zA-Z0-9_]+\.report(?:\.errors)?$/)
{
# Keep the reference WineTest reports for all VMs even if they are
# retired or scheduled for deletion.
diff --git a/testbot/bin/UpdateTaskLogs b/testbot/bin/UpdateTaskLogs
index c6f7b753d3..d29b42afb2 100755
--- a/testbot/bin/UpdateTaskLogs
+++ b/testbot/bin/UpdateTaskLogs
@@ -4,7 +4,7 @@
# Updates or recreates the reference reports for the specified tasks and the
# latest directory.
#
-# Copyright 2019 Francois Gouget
+# Copyright 2019-2020 Francois Gouget
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -146,7 +146,7 @@ if (defined $Usage)
{
print "Usage: $Name0 [--rebuild] [--log-only] [--debug] [--help] [JOBID [STEPNO [TASKNO]]]\n";
print "\n";
- print "Deletes, upgrades or recreates the reference reports and .err files for the specified tasks and the latest directory.\n";
+ print "Deletes, upgrades or recreates the reference reports and .errors files for the specified tasks and the latest directory.\n";
print "\n";
print "Where:\n";
print " --delete Delete generated files of both the latest directory and the\n";
@@ -158,7 +158,7 @@ if (defined $Usage)
print " reports are preserved. If these tasks don't have reference\n";
print " reports, an error is shown.\n";
print " Without this option only the missing reference reports and\n";
- print " .err files are added.\n";
+ print " .errors files are added.\n";
print " JOBID STEPNO TASKNO Only the tasks matching the specified JOBID, STEPNO and\n";
print " TASKNO will be modified.\n";
print " --log-only Only print errors to the log. By default they also go to stderr.\n";
@@ -199,26 +199,15 @@ sub Delete($;$)
return 1;
}
-sub BuildErrFile($$$$)
+sub BuildErrorsCache($$$$;$)
{
- my ($Dir, $ReportName, $IsWineTest, $TaskTimedOut) = @_;
+ my ($Dir, $LogName, $IsWineTest, $TaskTimedOut, $Task) = @_;
- my $TaskKey = Path2TaskKey($Dir);
-
- my $LogInfo = ParseWineTestReport("$Dir/$ReportName", $IsWineTest, $TaskTimedOut);
- return "$TaskKey: $LogInfo->{BadLog}" if (defined $LogInfo->{BadLog});
- return undef if (!@{$LogInfo->{Extra}});
-
- Debug("$TaskKey: Creating $ReportName.err\n");
- if (open(my $Log, ">", "$Dir/$ReportName.err"))
- {
- # Save the extra errors detected by ParseWineTestReport() in
- # $ReportName.err (see WineRunWineTest.pl).
- print $Log "$_\n" for (@{$LogInfo->{Extra}});
- close($Log);
- return undef;
- }
- return "Unable to open '$TaskKey/$ReportName' for reading: $!";
+ Debug(Path2TaskKey($Dir) .": Creating $LogName.errors\n");
+ my $LogInfo = $LogName =~ /\.report$/ ?
+ ParseWineTestReport("$Dir/$LogName", $IsWineTest, $TaskTimedOut) :
+ ParseTaskLog("$Dir/$LogName");
+ return CreateLogErrorsCache($LogInfo, $Task);
}
# Maps the reference report name to its full pathname.
@@ -266,7 +255,8 @@ sub MoveRefReport($$;$)
my ($RefDir, $RefName, $NewDir) = @_;
my $RefPath = "$RefDir/$RefName";
- return Delete("$RefPath.err", "orphaned") if (!-f $RefPath);
+ my $Rc = Delete("$RefPath.err");
+ return $Rc if (!-f $RefPath);
$NewDir ||= $RefDir;
my $NewName = $RefName;
@@ -280,14 +270,11 @@ sub MoveRefReport($$;$)
my $NewPath = "$NewDir/$NewName";
return 0 if ($RefPath eq $NewPath);
- my $Rc = 0;
my $TaskKey = Path2TaskKey($NewDir);
if (-f $NewPath and -M $NewPath <= -M $RefPath)
{
# A WineTest job has probably completed after the upgrade already
- $Rc += Delete($RefPath);
- $Rc += Delete("$RefPath.err");
- return $Rc;
+ return Delete($RefPath);
}
if (-f $NewPath)
@@ -297,16 +284,14 @@ sub MoveRefReport($$;$)
}
my $RelRefDir = ($RefDir eq $NewDir) ? "" : "../";
- Debug("$TaskKey: $RelRefDir$RefName* -> $NewName\n");
- foreach my $Suffix ("", ".err")
+ Debug("$TaskKey: $RelRefDir$RefName -> $NewName\n");
+ if (!rename($RefPath, $NewPath))
{
- next if (!-f "$RefPath$Suffix");
- next if (rename("$RefPath$Suffix", "$NewPath$Suffix"));
- Error "Could not move '$RefName$Suffix' to '$NewName$Suffix' for $TaskKey: $!\n";
- $Rc = 1;
+ Error "Could not move '$RefName' to '$NewName' for $TaskKey: $!\n";
+ return 1;
}
- return $Rc;
+ return 0;
}
sub ProcessTaskLogs($$$)
@@ -367,7 +352,11 @@ sub ProcessTaskLogs($$$)
# testbot.log is the only log which we expect to be empty.
# There is not much point keeping it if that's the case.
my $TestBotLog = "$TaskDir/testbot.log";
- $Rc += Delete($TestBotLog) if (-z $TestBotLog);
+ if (-z $TestBotLog and (!-f "$TestBotLog.errors" or -z _))
+ {
+ $Rc += Delete($TestBotLog);
+ $Rc += Delete("$TestBotLog.errors");
+ }
}
if (($OptDelete or $OptRebuild) and !$CollectOnly)
@@ -379,13 +368,13 @@ sub ProcessTaskLogs($$$)
my $RefReportName = $Task->GetRefReportName($ReportName);
my $RefReportPath = "$TaskDir/$RefReportName";
- if (-f $RefReportPath or -f "$RefReportPath.err")
+ if (-f $RefReportPath or -f "$RefReportPath.errors")
{
- if (!$OptDelete and !-f "$RefReportPath.err")
+ if (!$OptDelete and !-f "$RefReportPath.errors")
{
- # (Re)Build the .err file before adding the reference report to
+ # (Re)Build the .errors file before adding the reference report to
# latest/.
- my $ErrMessage = BuildErrFile($TaskDir, $RefReportName, 1, 0);
+ my $ErrMessage = BuildErrorsCache($TaskDir, $RefReportName, 1, 0);
if (defined $ErrMessage)
{
Error "$ErrMessage\n";
@@ -399,8 +388,16 @@ sub ProcessTaskLogs($$$)
}
$Rc += Delete($RefReportPath);
$Rc += Delete("$RefReportPath.err");
+ $Rc += Delete("$RefReportPath.errors");
$Rc += Delete("$TaskDir/$ReportName.err");
}
+
+ # And clean up the files derived from the task's logs
+ foreach my $LogName (@{GetLogFileNames($TaskDir, "+old")})
+ {
+ $Rc += Delete("$TaskDir/$LogName.err");
+ $Rc += Delete("$TaskDir/$LogName.errors");
+ }
}
if (!$OptDelete and !$CollectOnly and $Task->Status eq "completed")
@@ -409,7 +406,9 @@ sub ProcessTaskLogs($$$)
foreach my $ReportName (@{GetLogFileNames($TaskDir)})
{
next if ($ReportName !~ /\.report$/);
+
my $RefReportName = $Task->GetRefReportName($ReportName);
+ $Rc += Delete("$TaskDir/$RefReportName.err");
next if (-f "$TaskDir/$RefReportName");
my $LatestReportPath = $LatestReports{$RefReportName};
@@ -421,7 +420,7 @@ sub ProcessTaskLogs($$$)
else
{
Debug(TaskKeyStr($Task) .": Snapshotting $RefReportName from ". Path2TaskKey($LatestReportPath) ."\n");
- foreach my $Suffix ("", ".err")
+ foreach my $Suffix ("", ".errors")
{
unlink "$TaskDir/$RefReportName$Suffix";
if (-f "$LatestReportPath$Suffix" and
@@ -433,22 +432,42 @@ sub ProcessTaskLogs($$$)
}
}
}
+ }
- # And (re)build the .err files
- if ($Task->Status !~ /^(?:queued|running)$/)
+ if (!$OptDelete and !$CollectOnly and $Task->Status !~ /^(?:queued|running)$/)
+ {
+ # And (re)build the .errors files, even if Status != 'completed' for
+ # task.log and testbot.log.
+ my ($IsWineTest, $TaskTimedOut);
+ if ($Task->Started and $Task->Ended)
{
- my ($IsWineTest, $TaskTimedOut);
- if ($Task->Started and $Task->Ended)
+ my $Duration = $Task->Ended - $Task->Started;
+ $TaskTimedOut = $Duration > $Task->Timeout;
+ $IsWineTest = ($Step->Type eq "patch" or $Step->Type eq "suite");
+ }
+ foreach my $LogName (@{GetLogFileNames($TaskDir, "+old")})
+ {
+ $Rc += Delete("$TaskDir/$LogName.err");
+ if ($LogName =~ /\.report$/)
{
- my $Duration = $Task->Ended - $Task->Started;
- $TaskTimedOut = $Duration > $Task->Timeout;
- $IsWineTest = ($Step->Type eq "patch" or $Step->Type eq "suite");
+ # First for the reference report if any
+ my $RefReportName = $Task->GetRefReportName($LogName);
+ if (!-f "$TaskDir/$RefReportName.errors" and
+ -f "$TaskDir/$RefReportName")
+ {
+ my $ErrMessage = BuildErrorsCache($TaskDir, $RefReportName, 1, 0);
+ if (defined $ErrMessage)
+ {
+ Error "$ErrMessage\n";
+ $Rc = 1;
+ }
+ }
}
- foreach my $ReportName (@{GetLogFileNames($TaskDir)})
+
+ # Then for the report / log itself
+ if (!-f "$TaskDir/$LogName.errors")
{
- next if ($ReportName !~ /\.report$/);
- next if (-f "$TaskDir/$ReportName.err");
- my $ErrMessage = BuildErrFile($TaskDir, $ReportName, $IsWineTest, $TaskTimedOut);
+ my $ErrMessage = BuildErrorsCache($TaskDir, $LogName, $IsWineTest, $TaskTimedOut, $Task);
if (defined $ErrMessage)
{
Error "$ErrMessage\n";
@@ -500,34 +519,35 @@ sub ProcessLatestReports()
}
else
{
- # MoveRefReport() also renames .err files
+ # MoveRefReport() also deletes .err files
$Rc += MoveRefReport("$DataDir/latest", $RefReportName);
}
}
# Then perform cleanups and rebuild missing files
- foreach my $LatestReportPath (glob("$LatestGlob $LatestGlob.err"))
+ foreach my $LatestReportPath (glob("$LatestGlob $LatestGlob.errors"))
{
my $RefReportName = basename($LatestReportPath);
# Keep the regexp in sync with WineTestBot::Task::GetRefReportName()
- next if ($RefReportName !~ /^([a-zA-Z0-9_]+-job[0-9]+-[a-zA-Z0-9_]+\.report)(?:\.err)?$/);
+ next if ($RefReportName !~ /^([a-zA-Z0-9_]+-job[0-9]+-[a-zA-Z0-9_]+\.report)(?:\.errors)?$/);
$RefReportName = $1; # untaint
$LatestReportPath = "$DataDir/latest/$RefReportName";
+ $Rc += Delete("$LatestReportPath.err");
if ($OptDelete or $OptRebuild)
{
# These can be rebuilt from the task reports
$Rc += Delete($LatestReportPath);
- $Rc += Delete("$LatestReportPath.err");
+ $Rc += Delete("$LatestReportPath.errors");
}
elsif (!-f $LatestReportPath)
{
- $Rc += Delete("$LatestReportPath.err", "orphaned");
+ $Rc += Delete("$LatestReportPath.errors", "orphaned");
}
- elsif (!-f "$LatestReportPath.err")
+ elsif (!-f "$LatestReportPath.errors")
{
- # Build the missing .err file
- my $ErrMessage = BuildErrFile("$DataDir/latest", $RefReportName, 1, 0);
+ # Build the missing .errors file
+ my $ErrMessage = BuildErrorsCache("$DataDir/latest", $RefReportName, 1, 0);
if (defined $ErrMessage)
{
Error "$ErrMessage\n";
diff --git a/testbot/bin/WineRunBuild.pl b/testbot/bin/WineRunBuild.pl
index 45288af95a..e7a90aa4a3 100755
--- a/testbot/bin/WineRunBuild.pl
+++ b/testbot/bin/WineRunBuild.pl
@@ -443,6 +443,8 @@ if ($TA->GetFile("Build.log", "$TaskDir/task.log"))
# that explains why.
$NewStatus = "badbuild";
}
+ my $ErrMessage = CreateLogErrorsCache($LogInfo);
+ LogTaskError("$ErrMessage\n") if (defined $ErrMessage);
}
elsif (!defined $TAError)
{
diff --git a/testbot/bin/WineRunReconfig.pl b/testbot/bin/WineRunReconfig.pl
index 83c26ccd3c..74f618151f 100755
--- a/testbot/bin/WineRunReconfig.pl
+++ b/testbot/bin/WineRunReconfig.pl
@@ -443,6 +443,8 @@ if ($TA->GetFile("Reconfig.log", "$TaskDir/task.log"))
MakeSecureURL(GetTaskURL($JobId, $StepNo, $TaskNo)) ."\n");
$NewStatus = "badbuild";
}
+ my $ErrMessage = CreateLogErrorsCache($LogInfo);
+ LogTaskError("$ErrMessage\n") if (defined $ErrMessage);
}
elsif (!defined $TAError)
{
diff --git a/testbot/bin/WineRunTask.pl b/testbot/bin/WineRunTask.pl
index 59975c3df9..f55fa9f706 100755
--- a/testbot/bin/WineRunTask.pl
+++ b/testbot/bin/WineRunTask.pl
@@ -534,7 +534,13 @@ if (!defined $TA->Wait($Pid, $Timeout, $Keepalive))
}
Debug(Elapsed($Start), " Retrieving 'Task.log'\n");
-if (!$TA->GetFile("Task.log", "$TaskDir/task.log") and !defined $TAError)
+if ($TA->GetFile("Task.log", "$TaskDir/task.log"))
+{
+ my $LogInfo = ParseTaskLog("$TaskDir/task.log");
+ my $ErrMessage = CreateLogErrorsCache($LogInfo);
+ LogTaskError("$ErrMessage\n") if (defined $ErrMessage);
+}
+elsif (!defined $TAError)
{
$TAError = "An error occurred while retrieving the task log: ". $TA->GetLastError();
}
@@ -561,13 +567,8 @@ if ($TA->GetFile($RptFileName, "$TaskDir/$RptFileName"))
# $LogInfo->{Failures} can legitimately be undefined in case of a timeout
$TaskFailures += $LogInfo->{Failures} || 0;
- if (@{$LogInfo->{Extra}} and open(my $Log, ">", "$TaskDir/$RptFileName.err"))
- {
- # Save the extra errors detected by ParseWineTestReport() in
- # $RptFileName.err (see WineRunWineTest.pl).
- print $Log "$_\n" for (@{$LogInfo->{Extra}});
- close($Log);
- }
+ my $ErrMessage = CreateLogErrorsCache($LogInfo, $Task);
+ LogTaskError("$ErrMessage\n") if (defined $ErrMessage);
}
}
elsif (!defined $TAError)
diff --git a/testbot/bin/WineRunWineTest.pl b/testbot/bin/WineRunWineTest.pl
index 9d54745966..c35d6c0ae8 100755
--- a/testbot/bin/WineRunWineTest.pl
+++ b/testbot/bin/WineRunWineTest.pl
@@ -540,6 +540,8 @@ if ($TA->GetFile("Task.log", "$TaskDir/task.log"))
$TaskFailures = undef;
$PossibleCrash = 1;
}
+ my $ErrMessage = CreateLogErrorsCache($LogInfo);
+ LogTaskError("$ErrMessage\n") if (defined $ErrMessage);
}
elsif (!defined $TAError)
{
@@ -575,18 +577,8 @@ foreach my $RptFileName (@$ReportNames)
# $LogInfo->{Failures} can legitimately be undefined in case of a timeout
$TaskFailures += $LogInfo->{Failures} || 0;
- if (@{$LogInfo->{Extra}} and open(my $Log, ">", "$TaskDir/$RptFileName.err"))
- {
- # Save the extra errors detected by ParseWineTestReport() in
- # $RptFileName.err:
- # - This keep the .report file clean.
- # - Each .err file can be matched to its corresponding .report, even
- # if there are multiple .report files in the directory.
- # - The .err file can be moved to the latest directory next to the
- # reference report.
- print $Log "$_\n" for (@{$LogInfo->{Extra}});
- close($Log);
- }
+ my $ErrMessage = CreateLogErrorsCache($LogInfo, $Task);
+ LogTaskError("$ErrMessage\n") if (defined $ErrMessage);
}
}
elsif (!defined $TAError and
diff --git a/testbot/bin/WineSendLog.pl b/testbot/bin/WineSendLog.pl
index e0cd585b11..23930993cb 100755
--- a/testbot/bin/WineSendLog.pl
+++ b/testbot/bin/WineSendLog.pl
@@ -78,6 +78,54 @@ sub Error(@)
}
+#
+# Log errors caching
+#
+
+sub ParseTaskLogs($$)
+{
+ my ($Step, $Task) = @_;
+
+ my $TaskDir = $Task->GetDir();
+
+ # testbot.log is the only log which we expect to be empty.
+ # There is not much point keeping it if that's the case.
+ my $TestBotLog = "$TaskDir/testbot.log";
+ unlink $TestBotLog if (-z $TestBotLog and !-f "$TestBotLog.errors");
+
+ my ($IsWineTest, $TaskTimedOut);
+ if ($Task->Started and $Task->Ended)
+ {
+ my $Duration = $Task->Ended - $Task->Started;
+ $TaskTimedOut = $Duration > $Task->Timeout;
+ $IsWineTest = ($Step->Type eq "patch" or $Step->Type eq "suite");
+ }
+ foreach my $LogName (@{GetLogFileNames($TaskDir, "+old")})
+ {
+ next if (-f "$TaskDir/$LogName.errors");
+
+ my $LogInfo = $LogName =~ /\.report$/ ?
+ ParseWineTestReport("$TaskDir/$LogName", $IsWineTest, $TaskTimedOut) :
+ ParseTaskLog("$TaskDir/$LogName");
+ my $ErrMessage = CreateLogErrorsCache($LogInfo, $Task);
+ Error "$ErrMessage\n" if (defined $ErrMessage);
+ }
+}
+
+sub ParseJobLogs($)
+{
+ my ($Job) = @_;
+
+ foreach my $Step (@{$Job->Steps->GetItems()})
+ {
+ foreach my $Task (@{$Step->Tasks->GetItems()})
+ {
+ ParseTaskLogs($Step, $Task);
+ }
+ }
+}
+
+
#
# Reporting
#
@@ -98,27 +146,28 @@ sub GetTitle($$)
sub DumpLogAndErr($$)
{
- my ($File, $Path) = @_;
+ my ($File, $LogPath) = @_;
- my $PrintSeparator;
- foreach my $FileName ($Path, "$Path.err")
+ if (open(my $LogFile, "<", $LogPath))
{
- if (open(my $LogFile, "<", $FileName))
+ foreach my $Line (<$LogFile>)
{
- my $First = 1;
- foreach my $Line (<$LogFile>)
- {
- $Line =~ s/\s*$//;
- if ($First and $PrintSeparator)
- {
- print $File "\n";
- $First = 0;
- }
- print $File "$Line\n";
- }
- close($LogFile);
- $PrintSeparator = 1;
+ $Line =~ s/\s*$//;
+ print $File "$Line\n";
}
+ close($LogFile);
+ }
+
+ # And append the extra errors
+ my $LogInfo = LoadLogErrors($LogPath);
+ foreach my $GroupName (@{$LogInfo->{ErrGroupNames}})
+ {
+ my $Group = $LogInfo->{ErrGroups}->{$GroupName};
+ # Extra groups don't have a line number
+ next if ($Group->{LineNo});
+
+ print $File "\n$GroupName\n";
+ print $File "$_\n" for (@{$Group->{Errors}});
}
}
@@ -208,12 +257,13 @@ EOF
$JobErrors->{$Key}->{LogNames} = $LogNames;
foreach my $LogName (@$LogNames)
{
- my $LogInfo = GetLogErrors("$TaskDir/$LogName");
- next if (!$LogInfo->{ErrCount});
+ my $LogInfo = LoadLogErrors("$TaskDir/$LogName");
+ next if (!defined $LogInfo->{BadLog} and !$LogInfo->{ErrCount});
$JobErrors->{$Key}->{HasErrors} = 1;
$JobErrors->{$Key}->{$LogName} = $LogInfo;
print $Sendmail "\n=== ", GetTitle($StepTask, $LogName), " ===\n";
+ print $Sendmail "$LogInfo->{BadLog}\n" if (defined $LogInfo->{BadLog});
foreach my $GroupName (@{$LogInfo->{ErrGroupNames}})
{
@@ -292,35 +342,17 @@ EOF
# Skip if there are no errors
next if (!$LogInfo->{ErrCount});
- my $AllNew;
- my $RefReportPath = "$TaskDir/". $StepTask->GetRefReportName($LogName);
- TagNewErrors($RefReportPath, $LogInfo);
- if ($LogInfo->{NoRef})
- {
- # Test reports should have reference WineTest results and if not
- # reporting the errors as new would cause false positives.
- next if ($LogName =~ /\.report$/);
-
- # Build logs don't have reference logs so for them every error is new.
- $AllNew = 1;
- }
- elsif (!$LogInfo->{NewCount})
- {
- # There is no new error
- next;
- }
-
push @Messages, "\n=== ". GetTitle($StepTask, $LogName) ." ===\n";
foreach my $GroupName (@{$LogInfo->{ErrGroupNames}})
{
my $Group = $LogInfo->{ErrGroups}->{$GroupName};
- next if (!$AllNew and !$Group->{NewCount});
+ next if (!$Group->{NewCount});
push @Messages, ($GroupName ? "\n$GroupName:\n" : "\n");
foreach my $ErrIndex (0..@{$Group->{Errors}} - 1)
{
- if ($AllNew or $Group->{IsNew}->[$ErrIndex])
+ if ($Group->{IsNew}->[$ErrIndex])
{
push @Messages, "$Group->{Errors}->[$ErrIndex]\n";
}
@@ -511,6 +543,7 @@ if (!defined $Job)
# Analyze the log, notify the developer and the Patches website
#
+ParseJobLogs($Job);
SendLog($Job);
LogMsg "Log for job $JobId sent\n";
diff --git a/testbot/lib/WineTestBot/LogUtils.pm b/testbot/lib/WineTestBot/LogUtils.pm
index 66359a9dc7..9bde76c6c6 100644
--- a/testbot/lib/WineTestBot/LogUtils.pm
+++ b/testbot/lib/WineTestBot/LogUtils.pm
@@ -27,10 +27,11 @@ WineTestBot::LogUtils - Provides functions to parse task logs
use Exporter 'import';
-our @EXPORT = qw(GetLogFileNames GetLogLabel GetLogErrors TagNewErrors
+our @EXPORT = qw(GetLogFileNames GetLogLabel
GetLogLineCategory GetReportLineCategory
ParseTaskLog ParseWineTestReport
- SnapshotLatestReport UpdateLatestReport UpdateLatestReports);
+ SnapshotLatestReport UpdateLatestReport UpdateLatestReports
+ CreateLogErrorsCache LoadLogErrors);
use Algorithm::Diff;
use File::Basename;
@@ -624,14 +625,12 @@ sub GetLogFileNames($;$)
task.log testbot.log);
push @Globs, ("old_task.log", "old_testbot.log") if ($IncludeOld);
- my (@Logs, %Seen);
+ my @Logs;
foreach my $Glob (@Globs)
{
- foreach my $FileName (glob("'$Dir/$Glob*'"))
+ foreach my $FileName (glob("'$Dir/$Glob'"))
{
my $LogName = basename($FileName);
- $LogName =~ s/\.err$//;
- next if ($Seen{$LogName});
if ($LogName =~ /^([a-zA-Z0-9_]+\.report)$/)
{
$LogName = $1; # untaint
@@ -645,13 +644,8 @@ sub GetLogFileNames($;$)
# Not a valid log filename (where does this file come from?)
next;
}
- $Seen{$LogName} = 1;
- if ((-f "$Dir/$LogName" and !-z "$Dir/$LogName") or
- (-f "$Dir/$LogName.err" and !-z "$Dir/$LogName.err"))
- {
- push @Logs, $LogName;
- }
+ push @Logs, $LogName if (-f "$Dir/$LogName" and !-z _);
}
}
return \@Logs;
@@ -729,13 +723,20 @@ sub _AddLogGroup($$;$)
return $LogInfo->{ErrGroups}->{$GroupName};
}
-sub _AddLogError($$$;$)
+sub _AddLogError($$$;$$)
{
- my ($LogInfo, $ErrGroup, $Line, $LineNo) = @_;
+ my ($LogInfo, $ErrGroup, $Line, $LineNo, $IsNew) = @_;
push @{$ErrGroup->{Errors}}, $Line;
push @{$ErrGroup->{LineNos}}, $LineNo || 0;
$LogInfo->{ErrCount}++;
+ if ($IsNew)
+ {
+ my $ErrIndex = @{$ErrGroup->{Errors}} - 1;
+ $ErrGroup->{IsNew}->[$ErrIndex] = 1;
+ $ErrGroup->{NewCount}++;
+ $LogInfo->{NewCount}++;
+ }
}
=pod
@@ -743,9 +744,8 @@ sub _AddLogError($$$;$)
=item C<GetLogErrors()>
-Analyzes the specified log and associated error file to filter out unimportant
-messages and only return the errors, split by module (for Wine reports that's
-per dll / program being tested).
+Extracts the errors from the specified log file, split by module (for Wine
+reports that's per dll / program being tested).
Returns a hashtable containing:
=over
@@ -844,37 +844,177 @@ sub GetLogErrors($)
_AddLogError($LogInfo, $Group, $LogInfo->{BadLog});
}
- if (open(my $LogFile, "<", "$LogPath.err"))
+ return $LogInfo;
+}
+
+
+#
+# Log errors caching [Part 1]
+#
+
+=pod
+=over 12
+
+=item C<LoadLogErrors()>
+
+Loads the specified log errors file.
+
+The file contains two types of lines:
+* GroupName lines
+ <GroupName>
+ Where <GroupName> is a unique string which would typically be the name of a
+ WineTest dll or program, but may also be empty or be used to specify an
+ extra group errors. It must not start with a space.
+
+* Error lines
+ <Space> <New> <SrcLineNo> <Error>
+ Where:
+ - <Space> is a space, as well as the spaces in the line above.
+ - <New> is either 'n' for new errors, or 'o' for old ones.
+ - <SrcLineNo> is the 1-base line number of the error in the source log file.
+ If there is no source line then this should be 0.
+ - <Error> is the error message.
+
+Returns the errors in the same format as TagNewErrors().
+
+=back
+=cut
+
+sub LoadLogErrors($)
+{
+ my ($LogPath) = @_;
+
+ my $LogName = basename($LogPath);
+ my $LogInfo = {
+ LogName => $LogName,
+ LogPath => $LogPath,
+
+ ErrGroupNames => [],
+ ErrGroups => {},
+ };
+ $LogPath .= ".errors";
+
+ my $ErrorsFile;
+ if (!open($ErrorsFile, "<", $LogPath))
+ {
+ $LogInfo->{BadLog} = "Unable to open '$LogName' for reading: $!";
+ return $LogInfo;
+ }
+
+ my $CurGroup;
+ foreach my $Line (<$ErrorsFile>)
{
- $LogInfo->{ErrCount} ||= 0;
- # Add the related extra errors
- my $CurrentGroup;
- my $LineNo = 0;
- foreach my $Line (<$LogFile>)
+ chomp $Line;
+ my ($Type, $Property, $Value) = split / /, $Line, 3;
+ if ($Type eq "p")
{
- $LineNo++;
- $Line =~ s/\s*$//;
- if (!$CurrentGroup)
+ if (!defined $LogInfo->{$Property})
{
- # Note: $GroupName must not depend on the previous content as this
- # would break diffs.
- my $GroupName = $IsReport ? "Report errors" : "Task errors";
- $CurrentGroup = _AddLogGroup($LogInfo, $GroupName, $LineNo);
+ $LogInfo->{$Property} = $Value;
+ }
+ else
+ {
+ $LogInfo->{BadLog} = "Cannot set $Property = $Value because it is already set to $LogInfo->{$Property}";
+ last;
}
- _AddLogError($LogInfo, $CurrentGroup, $Line, $LineNo);
}
- close($LogFile);
- }
- elsif (-f "$LogPath.err")
- {
- $LogInfo->{BadLog} ||= "Could not open '$LogName.err' for reading: $!";
- my $Group = _AddLogGroup($LogInfo, "TestBot errors");
- _AddLogError($LogInfo, $Group, $LogInfo->{BadLog});
+ elsif ($Type eq "g")
+ {
+ $CurGroup = _AddLogGroup($LogInfo, $Value, $Property);
+ }
+ elsif (!$CurGroup)
+ {
+ $LogInfo->{BadLog} = "Got a $Type line with no group";
+ last;
+ }
+ elsif ($Type eq "o")
+ {
+ _AddLogError($LogInfo, $CurGroup, $Value, $Property);
+ }
+ elsif ($Type eq "n")
+ {
+ _AddLogError($LogInfo, $CurGroup, $Value, $Property, "new");
+ }
+ else
+ {
+ $LogInfo->{BadLog} = "Found an unknown line type ($Type)";
+ last;
+ }
}
+ close($ErrorsFile);
return $LogInfo;
}
+=pod
+=over 12
+
+=item C<_SaveLogErrors()>
+
+Saves the LogInfo structure to <LogName>.errors.
+
+The file contains lines of the form:
+ <type> <value1> <value2>
+
+The values depend on the <type> of the line. <type> and <value1> must not
+contain spaces while <value2> runs to the end of the line. More specifically
+the line formats are:
+=over
+
+=item p <name> <value>
+Property lines contain (name, value) pairs.
+Note that properties which can be calculated while reading the errors file
+are not saved (e.g. ErrCount and NewCount).
+
+=item g <lineno> <groupname>
+Group lines contain the group name and the line number of the first line of
+the group in the log. Note that the first line would typically not be an
+error line.
+A group line should be followed by the old and new error lines in this group.
+
+=item o <lineno> <line>
+Old error lines contain the line number of the error in the log and a verbatim
+copy of that line (with CR/LF converted to a simple LF).
+
+=item n <lineno> <line>
+The format for new error lines is identical to that for old errors but with a
+different type.
+
+=back
+=back
+=cut
+
+sub _SaveLogErrors($)
+{
+ my ($LogInfo) = @_;
+
+ my $ErrorsPath = "$LogInfo->{LogPath}.errors";
+ if (open(my $ErrorsFile, ">", $ErrorsPath))
+ {
+ foreach my $Name ("BadRef", "NoRef")
+ {
+ next if (!defined $LogInfo->{$Name});
+ print $ErrorsFile "p $Name $LogInfo->{$Name}\n";
+ }
+ foreach my $GroupName (@{$LogInfo->{ErrGroupNames}})
+ {
+ my $Group = $LogInfo->{ErrGroups}->{$GroupName};
+ print $ErrorsFile "g $Group->{LineNo} $GroupName\n";
+ foreach my $Index (0..@{$Group->{Errors}} - 1)
+ {
+ my $IsNew = $Group->{IsNew}->[$Index] ? "n" : "o";
+ print $ErrorsFile "$IsNew $Group->{LineNos}->[$Index] $Group->{Errors}->[$Index]\n";
+ }
+ }
+ close($ErrorsFile);
+
+ # Set the mtime so Janitor reaps both at the same time
+ utime time(), GetMTime($LogInfo->{LogPath}), $ErrorsPath;
+ return undef;
+ }
+ return "Could not open '$LogInfo->{LogName}.errors' for writing: $!";
+}
+
#
# New error detection
@@ -902,6 +1042,18 @@ sub _DumpDiff($$)
}
}
+sub MarkAllErrorsAsNew($)
+{
+ my ($LogInfo) = @_;
+
+ foreach my $Group (values %{$LogInfo->{ErrGroups}})
+ {
+ $Group->{NewCount} = @{$Group->{Errors}};
+ $Group->{IsNew}->[$_] = 1 for (0..$Group->{NewCount} - 1);
+ }
+ $LogInfo->{NewCount} = $LogInfo->{ErrCount};
+}
+
=pod
=over 12
@@ -980,7 +1132,7 @@ sub TagNewErrors($$)
return if (!$LogInfo->{ErrCount});
- my $RefInfo = GetLogErrors($RefLogPath);
+ my $RefInfo = LoadLogErrors($RefLogPath);
if (defined $RefInfo->{BadLog})
{
# Save the BadLog error but do not tag the errors as new: this is up to
@@ -1039,6 +1191,47 @@ sub TagNewErrors($$)
}
+#
+# Log errors caching [Part 2]
+#
+
+sub CreateLogErrorsCache($;$)
+{
+ my ($ParsedInfo, $Task) = @_;
+
+ my $LogInfo = GetLogErrors($ParsedInfo->{LogPath});
+
+ # Store ParseWineTestReport()'s extra errors into their own group
+ my $ExtraCount = $ParsedInfo->{Extra} ? @{$ParsedInfo->{Extra}} : 0;
+ if ($ExtraCount)
+ {
+ my $Group = _AddLogGroup($LogInfo, "Report validation errors");
+ $Group->{Errors} = $ParsedInfo->{Extra};
+ my @LineNos = (0) x $ExtraCount;
+ $Group->{LineNos} = \@LineNos;
+ $LogInfo->{ErrCount} += $ExtraCount;
+ }
+
+ return $LogInfo->{BadLog} if (defined $LogInfo->{BadLog});
+
+ if ($LogInfo->{LogName} !~ /\.report$/)
+ {
+ # Only test reports have reference WineTest results.
+ # So for other logs all errors are new.
+ MarkAllErrorsAsNew($LogInfo);
+ }
+ elsif ($Task and $LogInfo->{ErrCount})
+ {
+ my $RefReportPath = $Task->GetDir() ."/". $Task->GetRefReportName($LogInfo->{LogName});
+ TagNewErrors($RefReportPath, $LogInfo);
+ # Don't mark the errors as new if there is no reference WineTest report
+ # as this would cause false positives.
+ }
+
+ return _SaveLogErrors($LogInfo);
+}
+
+
#
# Reference report management
#
@@ -1067,7 +1260,7 @@ sub SnapshotLatestReport($$)
my @ErrMessages;
my $TaskDir = $Task->GetDir();
my $RefReportName = $Task->GetRefReportName($ReportName);
- foreach my $Suffix ("", ".err")
+ foreach my $Suffix ("", ".errors")
{
next if (!-f "$DataDir/latest/$RefReportName$Suffix");
@@ -1087,7 +1280,7 @@ sub UpdateLatestReport($$$)
my @ErrMessages;
my $RefReportName = $Task->GetRefReportName($ReportName);
- foreach my $Suffix ("", ".err")
+ foreach my $Suffix ("", ".errors")
{
# Add the new reference file even if it is empty.
next if (!-f "$SrcReportPath$Suffix");
diff --git a/testbot/lib/WineTestBot/StepsTasks.pm b/testbot/lib/WineTestBot/StepsTasks.pm
index f65e6a6327..463f15078a 100644
--- a/testbot/lib/WineTestBot/StepsTasks.pm
+++ b/testbot/lib/WineTestBot/StepsTasks.pm
@@ -67,13 +67,6 @@ sub GetTaskDir($)
return $self->GetStepDir() ."/". $self->TaskNo;
}
-# Keep in sync with WineTestBot::Task::GetRefReportName()
-sub GetRefReportName($$)
-{
- my ($self, $ReportName) = @_;
- return $self->VM->Name ."-job000000-$ReportName";
-}
-
sub GetTitle($)
{
my ($self) = @_;
diff --git a/testbot/lib/WineTestBot/Tasks.pm b/testbot/lib/WineTestBot/Tasks.pm
index 541b5558e3..f8b91d1c31 100644
--- a/testbot/lib/WineTestBot/Tasks.pm
+++ b/testbot/lib/WineTestBot/Tasks.pm
@@ -70,6 +70,7 @@ our @ISA = qw(WineTestBot::WineTestBotItem);
use File::Path;
use ObjectModel::BackEnd;
use WineTestBot::Config;
+use WineTestBot::LogUtils;
use WineTestBot::Missions;
@@ -172,6 +173,9 @@ sub _SetupTask($$)
}
close($Src);
}
+
+ my $LogInfo = ParseTaskLog("$Dir.new/old_$Filename");
+ CreateLogErrorsCache($LogInfo);
}
$self->RmTree();
diff --git a/testbot/web/JobDetails.pl b/testbot/web/JobDetails.pl
index 3dce91595d..ccf3410f5b 100644
--- a/testbot/web/JobDetails.pl
+++ b/testbot/web/JobDetails.pl
@@ -346,43 +346,36 @@ sub GenerateMoreInfoLink($$$$;$$)
print "<div class='TaskMoreInfoLink'>$Html</div>\n";
}
-sub GetErrorCategory($)
+sub GenerateFullLog($$$$)
{
- return "error";
-}
+ my ($self, $Dir, $LogName, $HideLog) = @_;
-sub GenerateFullLog($$$$;$)
-{
- my ($self, $FileName, $HideLog, $LogInfo, $Header) = @_;
+ my $LogInfo = LoadLogErrors("$Dir/$LogName");
my %NewLineNos;
- if ($LogInfo and $LogInfo->{NewCount})
+ if ($LogInfo->{ErrCount})
{
foreach my $GroupName (@{$LogInfo->{ErrGroupNames}})
{
my $Group = $LogInfo->{ErrGroups}->{$GroupName};
next if (!$Group->{NewCount});
- if (($FileName =~ /\.err$/) ==
- ($GroupName =~ /^(?:Report errors|Task errors|TestBot errors)$/))
+ for my $ErrIndex (0..@{$Group->{Errors}} - 1)
{
- for my $ErrIndex (0..@{$Group->{Errors}} - 1)
+ if ($Group->{IsNew}->[$ErrIndex])
{
- if ($Group->{IsNew}->[$ErrIndex])
- {
- $NewLineNos{$Group->{LineNos}->[$ErrIndex]} = 1;
- }
+ $NewLineNos{$Group->{LineNos}->[$ErrIndex]} = 1;
}
}
}
}
- my $GetCategory = $FileName =~ /\.err$/ ? \&GetErrorCategory :
- $FileName =~ /\.report$/ ? \&GetReportLineCategory :
+ my $GetCategory = $LogName =~ /\.report$/ ? \&GetReportLineCategory :
\&GetLogLineCategory;
my $LineNo = 0;
my $IsEmpty = 1;
- if (open(my $LogFile, "<", $FileName))
+ my $LineNo = 0;
+ if (open(my $LogFile, "<", "$Dir/$LogName"))
{
foreach my $Line (<$LogFile>)
{
@@ -390,7 +383,6 @@ sub GenerateFullLog($$$$;$)
$Line =~ s/\s*$//;
if ($IsEmpty)
{
- print $Header if (defined $Header);
print "<pre$HideLog><code>";
$IsEmpty = 0;
}
@@ -405,8 +397,32 @@ sub GenerateFullLog($$$$;$)
}
close($LogFile);
}
- print "</code></pre>\n" if (!$IsEmpty);
+ # And append the extra errors
+ foreach my $GroupName (@{$LogInfo->{ErrGroupNames}})
+ {
+ my $Group = $LogInfo->{ErrGroups}->{$GroupName};
+ # Extra groups don't have a line number
+ next if ($Group->{LineNo});
+
+ print "<div class='LogDllName'>$GroupName</div>\n";
+ my $i = 0;
+ for my $i (0..@{$Group->{Errors}} - 1)
+ {
+ if ($IsEmpty)
+ {
+ print "<pre$HideLog><code>";
+ $IsEmpty = 0;
+ }
+
+ my $Line = $Group->{Errors}->[$i];
+ my $Category = $Group->{IsNew}->[$i] ? "new" : "error";
+ my $Html = $self->escapeHTML($Line);
+ print "<span class='log-$Category'>$Html</span>\n";
+ }
+ }
+
+ print "</code></pre>\n" if (!$IsEmpty);
return $IsEmpty;
}
@@ -486,48 +502,26 @@ EOF
# Show this log in full, highlighting the important lines
#
- my $LogInfo;
- my $LogFileName = "$TaskDir/$MoreInfo->{Full}";
- if ($MoreInfo->{Full} =~ /\.report$/)
- {
- $LogInfo = GetLogErrors($LogFileName);
- if ($LogInfo->{ErrCount})
- {
- # Identify new errors in test reports
- my $RefReportPath = "$TaskDir/". $StepTask->GetRefReportName($MoreInfo->{Full});
- TagNewErrors($RefReportPath, $LogInfo);
- }
- }
-
my ($Action, $Url) = $self->GetMoreInfoLink($Key, GetLogLabel($MoreInfo->{Full}), "Full", $MoreInfo->{Full});
$Url = $self->CGI->escapeHTML($Url);
my $HideLog = $Action eq "Hide" ? " ondblclick='HideLog(event, \"$Url\")'" : "";
- my $LogIsEmpty = $self->GenerateFullLog($LogFileName, $HideLog, $LogInfo);
- my $EmptyDiag;
+ my $LogIsEmpty = $self->GenerateFullLog($TaskDir, $MoreInfo->{Full}, $HideLog);
if ($LogIsEmpty)
{
if ($StepTask->Status eq "canceled")
{
- $EmptyDiag = "No log, task was canceled\n";
+ print "No log, task was canceled\n";
}
elsif ($StepTask->Status eq "skipped")
{
- $EmptyDiag = "No log, task skipped\n";
+ print "No log, task skipped\n";
}
else
{
print "Empty log\n";
- $LogIsEmpty = 0;
}
}
-
- # And append the associated extra errors
- my $ErrHeader = $MoreInfo->{Full} =~ /\.report/ ? "report" : "task";
- $ErrHeader = "old $ErrHeader" if ($MoreInfo->{Full} =~ /^old_/);
- $ErrHeader = "<div class='HrTitle'>". ucfirst($ErrHeader) ." errors<div class='HrLine'></div></div>";
- my $ErrIsEmpty = $self->GenerateFullLog("$LogFileName.err", $HideLog, $LogInfo, $ErrHeader);
- print $EmptyDiag if ($ErrIsEmpty and defined $EmptyDiag);
}
else
{
@@ -540,7 +534,7 @@ EOF
foreach my $LogName (@{$MoreInfo->{Logs}})
{
next if ($LogName =~ /^old_/);
- my $LogInfo = GetLogErrors("$TaskDir/$LogName");
+ my $LogInfo = LoadLogErrors("$TaskDir/$LogName");
next if (!$LogInfo->{ErrCount});
$LogInfos->{$LogName} = $LogInfo;
}
@@ -560,13 +554,6 @@ EOF
}
my $LogInfo = $LogInfos->{$LogName};
- if ($LogName =~ /\.report$/)
- {
- # For test reports try to identify the new errors
- my $RefReportPath = "$TaskDir/". $StepTask->GetRefReportName($LogName);
- TagNewErrors($RefReportPath, $LogInfo);
- }
-
foreach my $GroupName (@{$LogInfo->{ErrGroupNames}})
{
print "<div class='LogDllName'>$GroupName</div>\n" if ($GroupName);
--
2.20.1
1
1
[PATCH v2] d3d9: Return a stub interface from Direct3DShaderValidatorCreate9().
by Zebediah Figura 09 Feb '20
by Zebediah Figura 09 Feb '20
09 Feb '20
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46735
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/d3d9/d3d9_main.c | 111 +++++++++++++++++++++++++++++++++++++--
dlls/d3d9/tests/device.c | 64 ++++++++++++++++++++++
2 files changed, 171 insertions(+), 4 deletions(-)
diff --git a/dlls/d3d9/d3d9_main.c b/dlls/d3d9/d3d9_main.c
index 21df2a34cd2..5832841f7f8 100644
--- a/dlls/d3d9/d3d9_main.c
+++ b/dlls/d3d9/d3d9_main.c
@@ -75,18 +75,121 @@ HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9E
return D3D_OK;
}
+/* The callback is called on any error encountered during validation, including
+ * improper IDirect3DShaderValidator9 method calls.
+ * - "file" and "line" are passed through directly from Instruction(). "line"
+ * is provably 32-bit, as 64-bit values passed to Instruction() will be
+ * truncated.
+ * - "arg3" has been observed to be at least 0, 2, and 6. The integer size is
+ * not known.
+ * - "message_id" is a numeric error code. fxc.exe adds 5000 before printing
+ * it. The integer size is not known.
+ * - "context" is passed through directly from Begin().
+ *
+ * Improper calls to IDirect3DShaderValidator9 methods, or other errors not
+ * generated by specific Instruction() calls, yield NULL as the file, and
+ * either 0 or -1 as the line.
+ *
+ * The callback return type is not known, but programs (fxc.exe, The Sims 2)
+ * seem to consistently return 0.
+ *
+ * The interface and method names below are derived from the messages that
+ * native d3d9 prints on said improper method calls.
+ *
+ * Calls to Begin(), Instruction(), End() have been observed to return S_OK and
+ * E_FAIL. E_FAIL is not always returned if an error message is handed to the
+ * callback. */
+
+typedef HRESULT (WINAPI *shader_validator_cb)(const char *file, int line,
+ DWORD_PTR arg3, DWORD_PTR message_id, const char *message, void *context);
+
+typedef struct IDirect3DShaderValidator9 IDirect3DShaderValidator9;
+
+typedef struct
+{
+ HRESULT (WINAPI *QueryInterface)(IDirect3DShaderValidator9 *iface, REFIID iid, void **out);
+ ULONG (WINAPI *AddRef)(IDirect3DShaderValidator9 *iface);
+ ULONG (WINAPI *Release)(IDirect3DShaderValidator9 *iface);
+ HRESULT (WINAPI *Begin)(IDirect3DShaderValidator9 *iface, shader_validator_cb callback, void *context, DWORD_PTR arg3);
+ HRESULT (WINAPI *Instruction)(IDirect3DShaderValidator9 *iface, const char *file, int line, const DWORD *code, DWORD code_len);
+ HRESULT (WINAPI *End)(IDirect3DShaderValidator9 *iface);
+} IDirect3DShaderValidator9Vtbl;
+
+struct IDirect3DShaderValidator9
+{
+ const IDirect3DShaderValidator9Vtbl *vtbl;
+};
+
+static HRESULT WINAPI shader_validator_QueryInterface(IDirect3DShaderValidator9 *iface, REFIID iid, void **out)
+{
+ TRACE("iface %p, iid %p, out %p.\n", iface, iid, out);
+
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI shader_validator_AddRef(IDirect3DShaderValidator9 *iface)
+{
+ TRACE("iface %p.\n", iface);
+ return 2;
+}
+
+static ULONG WINAPI shader_validator_Release(IDirect3DShaderValidator9 *iface)
+{
+ TRACE("iface %p.\n", iface);
+ return 1;
+}
+
+/* The size and type of the third argument is not known. The Sims 2 passes 0;
+ * fxc.exe passes 1. */
+static HRESULT WINAPI shader_validator_Begin(IDirect3DShaderValidator9 *iface,
+ shader_validator_cb callback, void *context, DWORD_PTR arg3)
+{
+ FIXME("iface %p, callback %p, context %p, arg3 %#Ix, stub!\n", iface, callback, context, arg3);
+ return S_OK;
+}
+
+/* - "file" and "line" are passed directly through to the callback.
+ * - "code" comprises a single instruction; the program must determine its
+ * length.
+ * - "code_len" is in DWORDs. */
+static HRESULT WINAPI shader_validator_Instruction(IDirect3DShaderValidator9 *iface,
+ const char *file, int line, const DWORD *code, DWORD code_len)
+{
+ FIXME("iface %p, file %s, line %u, code %p, code_len %u, stub!\n", iface, debugstr_a(file), line, code, code_len);
+ return S_OK;
+}
+
+static HRESULT WINAPI shader_validator_End(IDirect3DShaderValidator9 *iface)
+{
+ FIXME("iface %p, stub!\n", iface);
+ return S_OK;
+}
+
+static const IDirect3DShaderValidator9Vtbl shader_validator_vtbl =
+{
+ shader_validator_QueryInterface,
+ shader_validator_AddRef,
+ shader_validator_Release,
+ shader_validator_Begin,
+ shader_validator_Instruction,
+ shader_validator_End,
+};
+
+static IDirect3DShaderValidator9 shader_validator = {&shader_validator_vtbl};
+
/*******************************************************************
* Direct3DShaderValidatorCreate9 (D3D9.@)
*
* No documentation available for this function.
* SDK only says it is internal and shouldn't be used.
*/
-void* WINAPI Direct3DShaderValidatorCreate9(void)
+IDirect3DShaderValidator9 * WINAPI Direct3DShaderValidatorCreate9(void)
{
- static int once;
+ TRACE("Returning validator %p.\n", &shader_validator);
- if (!once++) FIXME("stub\n");
- return NULL;
+ return &shader_validator;
}
/***********************************************************************
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index 38b2dbcb3a3..59dfb98483a 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -53,6 +53,8 @@ struct device_desc
static DEVMODEW registry_mode;
+static void *(WINAPI *Direct3DShaderValidatorCreate9)(void);
+
static const DWORD simple_vs[] =
{
0xfffe0101, /* vs_1_1 */
@@ -13434,8 +13436,67 @@ static void test_multi_adapter(void)
IDirect3D9_Release(d3d);
}
+typedef HRESULT (WINAPI *shader_validator_cb)(const char *file, int line,
+ DWORD_PTR arg3, DWORD_PTR message_id, const char *message, void *context);
+
+typedef struct IDirect3DShaderValidator9 IDirect3DShaderValidator9;
+
+typedef struct
+{
+ HRESULT (WINAPI *QueryInterface)(IDirect3DShaderValidator9 *iface, REFIID iid, void **out);
+ ULONG (WINAPI *AddRef)(IDirect3DShaderValidator9 *iface);
+ ULONG (WINAPI *Release)(IDirect3DShaderValidator9 *iface);
+ HRESULT (WINAPI *Begin)(IDirect3DShaderValidator9 *iface, shader_validator_cb callback, void *context, DWORD_PTR arg3);
+ HRESULT (WINAPI *Instruction)(IDirect3DShaderValidator9 *iface, const char *file, int line, const DWORD *code, DWORD code_len);
+ HRESULT (WINAPI *End)(IDirect3DShaderValidator9 *iface);
+} IDirect3DShaderValidator9Vtbl;
+
+struct IDirect3DShaderValidator9
+{
+ const IDirect3DShaderValidator9Vtbl *vtbl;
+};
+
+HRESULT WINAPI test_shader_validator_cb(const char *file, int line, DWORD_PTR arg3,
+ DWORD_PTR message_id, const char *message, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return S_OK;
+}
+
+static void test_shader_validator(void)
+{
+ IDirect3DShaderValidator9 *validator;
+ ULONG refcount;
+ HRESULT hr;
+
+ validator = Direct3DShaderValidatorCreate9();
+
+ hr = validator->vtbl->Begin(validator, test_shader_validator_cb, NULL, 0);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[0], 1);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[1], 3);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[4], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[8], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[12], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[16], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[20], 1);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->End(validator);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ refcount = validator->vtbl->Release(validator);
+ todo_wine ok(!refcount, "Validator has %u references left.\n", refcount);
+}
+
START_TEST(device)
{
+ HMODULE d3d9_handle = GetModuleHandleA("d3d9.dll");
WNDCLASSA wc = {0};
IDirect3D9 *d3d9;
DEVMODEW current_mode;
@@ -13463,6 +13524,8 @@ START_TEST(device)
wc.lpszClassName = "d3d9_test_wc";
RegisterClassA(&wc);
+ Direct3DShaderValidatorCreate9 = (void *)GetProcAddress(d3d9_handle, "Direct3DShaderValidatorCreate9");
+
test_get_set_vertex_declaration();
test_get_declaration();
test_fvf_decl_conversion();
@@ -13562,6 +13625,7 @@ START_TEST(device)
test_vertex_buffer_read_write();
test_get_display_mode();
test_multi_adapter();
+ test_shader_validator();
UnregisterClassA("d3d9_test_wc", GetModuleHandleA(NULL));
}
--
2.25.0
2
1
[PATCH] d3d9: Return a stub interface from Direct3DShaderValidatorCreate9().
by Zebediah Figura 09 Feb '20
by Zebediah Figura 09 Feb '20
09 Feb '20
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46735
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/d3d9/d3d9_main.c | 107 +++++++++++++++++++++++++++++++++++++--
dlls/d3d9/tests/device.c | 64 +++++++++++++++++++++++
2 files changed, 167 insertions(+), 4 deletions(-)
diff --git a/dlls/d3d9/d3d9_main.c b/dlls/d3d9/d3d9_main.c
index 21df2a34cd2..a2e09ca1dfb 100644
--- a/dlls/d3d9/d3d9_main.c
+++ b/dlls/d3d9/d3d9_main.c
@@ -75,18 +75,117 @@ HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9E
return D3D_OK;
}
+/* The callback is called on any error encountered during validation, including
+ * improper IDirect3DShaderValidator9 method calls.
+ * - "file" and "line" are passed through directly from Instruction(). "line"
+ * is provably 32-bit, as 64-bit values passed to Instruction() will be
+ * truncated.
+ * - "arg3" has been observed to be at least 0, 2, and 6. The integer size is
+ * not known.
+ * - "message_id" is a numeric error code. fxc.exe adds 5000 before printing
+ * it. The integer size is not known.
+ * - "context" is passed through directly from Begin().
+ *
+ * Improper calls to IDirect3DShaderValidator9 methods, or other errors not
+ * generated by specific Instruction() calls, yield NULL as the file, and
+ * either 0 or -1 as the line.
+ *
+ * The callback return type is not known, but programs (fxc.exe, The Sims 2)
+ * seem to consistently return 0.
+ *
+ * The interface and method names below are derived from the messages that
+ * native d3d9 prints on said improper method calls. */
+
+typedef HRESULT (WINAPI *shader_validator_cb)(const char *file, int line,
+ DWORD_PTR arg3, DWORD_PTR message_id, const char *message, void *context);
+
+typedef struct IDirect3DShaderValidator9 IDirect3DShaderValidator9;
+
+typedef struct
+{
+ HRESULT WINAPI (*QueryInterface)(IDirect3DShaderValidator9 *iface, REFIID iid, void **out);
+ ULONG WINAPI (*AddRef)(IDirect3DShaderValidator9 *iface);
+ ULONG WINAPI (*Release)(IDirect3DShaderValidator9 *iface);
+ HRESULT WINAPI (*Begin)(IDirect3DShaderValidator9 *iface, shader_validator_cb callback, void *context, DWORD_PTR arg3);
+ HRESULT WINAPI (*Instruction)(IDirect3DShaderValidator9 *iface, const char *file, int line, const DWORD *code, DWORD code_len);
+ HRESULT WINAPI (*End)(IDirect3DShaderValidator9 *iface);
+} IDirect3DShaderValidator9Vtbl;
+
+struct IDirect3DShaderValidator9
+{
+ const IDirect3DShaderValidator9Vtbl *vtbl;
+};
+
+static HRESULT WINAPI shader_validator_QueryInterface(IDirect3DShaderValidator9 *iface, REFIID iid, void **out)
+{
+ TRACE("iface %p, iid %p, out %p.\n", iface, iid, out);
+
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI shader_validator_AddRef(IDirect3DShaderValidator9 *iface)
+{
+ TRACE("iface %p.\n", iface);
+ return 2;
+}
+
+static ULONG WINAPI shader_validator_Release(IDirect3DShaderValidator9 *iface)
+{
+ TRACE("iface %p.\n", iface);
+ return 1;
+}
+
+/* The size and type of the third argument is not known. The Sims 2 passes 0;
+ * fxc.exe passes 1. */
+static HRESULT WINAPI shader_validator_Begin(IDirect3DShaderValidator9 *iface,
+ shader_validator_cb callback, void *context, DWORD_PTR arg3)
+{
+ FIXME("iface %p, callback %p, context %p, arg3 %#Ix, stub!\n", iface, callback, context, arg3);
+ return S_OK;
+}
+
+/* - "file" and "line" are passed directly through to the callback.
+ * - "code" comprises a single instruction; the program must determine its
+ * length.
+ * - "code_len" is in DWORDs. */
+static HRESULT WINAPI shader_validator_Instruction(IDirect3DShaderValidator9 *iface,
+ const char *file, int line, const DWORD *code, DWORD code_len)
+{
+ FIXME("iface %p, file %s, line %u, code %p, code_len %u, stub!\n", iface, debugstr_a(file), line, code, code_len);
+ return S_OK;
+}
+
+static HRESULT WINAPI shader_validator_End(IDirect3DShaderValidator9 *iface)
+{
+ FIXME("iface %p, stub!\n", iface);
+ return S_OK;
+}
+
+static const IDirect3DShaderValidator9Vtbl shader_validator_vtbl =
+{
+ shader_validator_QueryInterface,
+ shader_validator_AddRef,
+ shader_validator_Release,
+ shader_validator_Begin,
+ shader_validator_Instruction,
+ shader_validator_End,
+};
+
+static IDirect3DShaderValidator9 shader_validator = {&shader_validator_vtbl};
+
/*******************************************************************
* Direct3DShaderValidatorCreate9 (D3D9.@)
*
* No documentation available for this function.
* SDK only says it is internal and shouldn't be used.
*/
-void* WINAPI Direct3DShaderValidatorCreate9(void)
+IDirect3DShaderValidator9 * WINAPI Direct3DShaderValidatorCreate9(void)
{
- static int once;
+ TRACE("Returning validator %p.\n", &shader_validator);
- if (!once++) FIXME("stub\n");
- return NULL;
+ return &shader_validator;
}
/***********************************************************************
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index 38b2dbcb3a3..6fbec0c2fd2 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -53,6 +53,8 @@ struct device_desc
static DEVMODEW registry_mode;
+static void *(WINAPI *Direct3DShaderValidatorCreate9)(void);
+
static const DWORD simple_vs[] =
{
0xfffe0101, /* vs_1_1 */
@@ -13434,8 +13436,67 @@ static void test_multi_adapter(void)
IDirect3D9_Release(d3d);
}
+typedef HRESULT (WINAPI *shader_validator_cb)(const char *file, int line,
+ DWORD_PTR arg3, DWORD_PTR message_id, const char *message, void *context);
+
+typedef struct IDirect3DShaderValidator9 IDirect3DShaderValidator9;
+
+typedef struct
+{
+ HRESULT WINAPI (*QueryInterface)(IDirect3DShaderValidator9 *iface, REFIID iid, void **out);
+ ULONG WINAPI (*AddRef)(IDirect3DShaderValidator9 *iface);
+ ULONG WINAPI (*Release)(IDirect3DShaderValidator9 *iface);
+ HRESULT WINAPI (*Begin)(IDirect3DShaderValidator9 *iface, shader_validator_cb callback, void *context, DWORD_PTR arg3);
+ HRESULT WINAPI (*Instruction)(IDirect3DShaderValidator9 *iface, const char *file, int line, const DWORD *code, DWORD code_len);
+ HRESULT WINAPI (*End)(IDirect3DShaderValidator9 *iface);
+} IDirect3DShaderValidator9Vtbl;
+
+struct IDirect3DShaderValidator9
+{
+ const IDirect3DShaderValidator9Vtbl *vtbl;
+};
+
+HRESULT WINAPI test_shader_validator_cb(const char *file, int line, DWORD_PTR arg3,
+ DWORD_PTR message_id, const char *message, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return S_OK;
+}
+
+static void test_shader_validator(void)
+{
+ IDirect3DShaderValidator9 *validator;
+ ULONG refcount;
+ HRESULT hr;
+
+ validator = Direct3DShaderValidatorCreate9();
+
+ hr = validator->vtbl->Begin(validator, test_shader_validator_cb, NULL, 0);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[0], 1);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[1], 3);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[4], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[8], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[12], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[16], 4);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->Instruction(validator, NULL, 0, &simple_vs[20], 1);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = validator->vtbl->End(validator);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ refcount = validator->vtbl->Release(validator);
+ todo_wine ok(!refcount, "Validator has %u references left.\n", refcount);
+}
+
START_TEST(device)
{
+ HMODULE d3d9_handle = GetModuleHandleA("d3d9.dll");
WNDCLASSA wc = {0};
IDirect3D9 *d3d9;
DEVMODEW current_mode;
@@ -13463,6 +13524,8 @@ START_TEST(device)
wc.lpszClassName = "d3d9_test_wc";
RegisterClassA(&wc);
+ Direct3DShaderValidatorCreate9 = (void *)GetProcAddress(d3d9_handle, "Direct3DShaderValidatorCreate9");
+
test_get_set_vertex_declaration();
test_get_declaration();
test_fvf_decl_conversion();
@@ -13562,6 +13625,7 @@ START_TEST(device)
test_vertex_buffer_read_write();
test_get_display_mode();
test_multi_adapter();
+ test_shader_validator();
UnregisterClassA("d3d9_test_wc", GetModuleHandleA(NULL));
}
--
2.25.0
3
3
09 Feb '20
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/ieframe/tests/webbrowser.c | 102 +++++++++++++-------------------
1 file changed, 42 insertions(+), 60 deletions(-)
diff --git a/dlls/ieframe/tests/webbrowser.c b/dlls/ieframe/tests/webbrowser.c
index 0195851bda..0e150e0851 100644
--- a/dlls/ieframe/tests/webbrowser.c
+++ b/dlls/ieframe/tests/webbrowser.c
@@ -168,7 +168,7 @@ static HWND container_hwnd, shell_embedding_hwnd;
static BOOL is_downloading, do_download, is_first_load, use_container_olecmd, test_close, is_http, use_container_dochostui;
static HRESULT hr_dochost_TranslateAccelerator = E_NOTIMPL;
static HRESULT hr_site_TranslateAccelerator = E_NOTIMPL;
-static const char *current_url;
+static const WCHAR *current_url;
static int wb_version, expect_update_commands_enable, set_update_commands_enable;
static BOOL nav_back_todo, nav_forward_todo; /* FIXME */
@@ -208,13 +208,6 @@ static BOOL is_lang_english(void)
return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
}
-static int strcmp_wa(LPCWSTR strw, const char *stra)
-{
- CHAR buf[512];
- WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
- return lstrcmpA(stra, buf);
-}
-
static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2)
{
IUnknown *unk1, *unk2;
@@ -230,18 +223,6 @@ static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2)
return unk1 == unk2;
}
-static BSTR a2bstr(const char *str)
-{
- BSTR ret;
- int len;
-
- len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
- ret = SysAllocStringLen(NULL, len);
- MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
-
- return ret;
-}
-
#define create_webbrowser() _create_webbrowser(__LINE__)
static IWebBrowser2 *_create_webbrowser(unsigned line)
{
@@ -257,7 +238,7 @@ static IWebBrowser2 *_create_webbrowser(unsigned line)
}
#define test_LocationURL(a,b) _test_LocationURL(__LINE__,a,b)
-static void _test_LocationURL(unsigned line, IWebBrowser2 *wb, const char *exurl)
+static void _test_LocationURL(unsigned line, IWebBrowser2 *wb, const WCHAR *exurl)
{
BSTR url = (void*)0xdeadbeef;
HRESULT hres;
@@ -266,7 +247,7 @@ static void _test_LocationURL(unsigned line, IWebBrowser2 *wb, const char *exurl
ok_(__FILE__,line) (hres == (*exurl ? S_OK : S_FALSE), "get_LocationURL failed: %08x\n", hres);
if (SUCCEEDED(hres))
{
- ok_(__FILE__,line) (!strcmp_wa(url, exurl), "unexpected URL: %s\n", wine_dbgstr_w(url));
+ ok_(__FILE__,line) (!lstrcmpW(url, exurl), "unexpected URL: %s\n", wine_dbgstr_w(url));
SysFreeString(url);
}
}
@@ -726,8 +707,8 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const
ok(V_VT(V_VARIANTREF(url)) == VT_BSTR, "V_VT(V_VARIANTREF(url))=%d, expected VT_BSTR\n",
V_VT(V_VARIANTREF(url)));
ok(V_BSTR(V_VARIANTREF(url)) != NULL, "V_BSTR(V_VARIANTREF(url)) == NULL\n");
- ok(!strcmp_wa(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n",
- wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), current_url);
+ ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n",
+ wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), wine_dbgstr_w(current_url));
}
ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n",
@@ -792,7 +773,7 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const
ok(V_VT(V_VARIANTREF(headers)) == VT_BSTR, "V_VT(V_VARIANTREF(headers))=%d, expected VT_BSTR\n",
V_VT(V_VARIANTREF(headers)));
str = V_BSTR(V_VARIANTREF(headers));
- ok(!str || !strcmp_wa(str, "Referer: http://test.winehq.org/tests/hello.html\r\n"),
+ ok(!str || !lstrcmpW(str, L"Referer: http://test.winehq.org/tests/hello.html\r\n"),
"V_BSTR(V_VARIANTREF(headers)) = %s, expected NULL\n", wine_dbgstr_w(str));
}
@@ -816,7 +797,8 @@ static void test_navigatecomplete2(DISPPARAMS *dp)
ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg));
v = V_VARIANTREF(dp->rgvarg);
ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v));
- ok(!strcmp_wa(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), current_url);
+ ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)),
+ wine_dbgstr_w(current_url));
ok(V_VT(dp->rgvarg+1) == VT_DISPATCH, "V_VT(dp->rgvarg+1) = %d\n", V_VT(dp->rgvarg+1));
ok(V_DISPATCH(dp->rgvarg+1) == (IDispatch*)wb, "V_DISPATCH=%p, wb=%p\n", V_DISPATCH(dp->rgvarg+1), wb);
@@ -839,7 +821,8 @@ static void test_documentcomplete(DISPPARAMS *dp)
ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg));
v = V_VARIANTREF(dp->rgvarg);
ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v));
- ok(!strcmp_wa(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), current_url);
+ ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)),
+ wine_dbgstr_w(current_url));
ok(V_VT(dp->rgvarg+1) == VT_DISPATCH, "V_VT(dp->rgvarg+1) = %d\n", V_VT(dp->rgvarg+1));
ok(V_DISPATCH(dp->rgvarg+1) == (IDispatch*)wb, "V_DISPATCH=%p, wb=%p\n", V_DISPATCH(dp->rgvarg+1), wb);
@@ -2463,7 +2446,7 @@ static void test_ie_funcs(IWebBrowser2 *wb)
hres = IWebBrowser2_get_Name(wb, &sName);
ok(hres == S_OK, "getName failed: %08x, expected S_OK\n", hres);
if (is_lang_english())
- ok(!strcmp_wa(sName, "Microsoft Web Browser Control"), "got '%s', expected 'Microsoft Web Browser Control'\n", wine_dbgstr_w(sName));
+ ok(!lstrcmpW(sName, L"Microsoft Web Browser Control"), "got '%s', expected 'Microsoft Web Browser Control'\n", wine_dbgstr_w(sName));
else /* Non-English cannot be blank. */
ok(sName!=NULL, "get_Name return a NULL string.\n");
SysFreeString(sName);
@@ -2757,20 +2740,20 @@ static void test_ConnectionPoint(IWebBrowser2 *unk, BOOL init)
IConnectionPoint_Release(point);
}
-static void test_Navigate2(IWebBrowser2 *webbrowser, const char *nav_url)
+static void test_Navigate2(IWebBrowser2 *webbrowser, const WCHAR *nav_url)
{
VARIANT url;
BOOL is_file;
HRESULT hres;
- test_LocationURL(webbrowser, is_first_load ? "" : current_url);
+ test_LocationURL(webbrowser, is_first_load ? L"" : current_url);
test_ready_state(is_first_load ? READYSTATE_UNINITIALIZED : READYSTATE_COMPLETE, VARIANT_FALSE);
is_http = !memcmp(nav_url, "http:", 5);
V_VT(&url) = VT_BSTR;
- V_BSTR(&url) = a2bstr(current_url = nav_url);
+ V_BSTR(&url) = SysAllocString(current_url = nav_url);
- if((is_file = !strncasecmp(nav_url, "file://", 7)))
+ if((is_file = !wcsnicmp(nav_url, L"file://", 7)))
current_url = nav_url + 7;
if(is_first_load) {
@@ -3178,14 +3161,14 @@ static void test_IServiceProvider(IWebBrowser2 *unk)
IServiceProvider_Release(servprov);
}
-static void test_put_href(IWebBrowser2 *unk, const char *url)
+static void test_put_href(IWebBrowser2 *unk, const WCHAR *url)
{
IHTMLLocation *location;
IHTMLDocument2 *doc;
BSTR str;
HRESULT hres;
- trace("put_href(%s)...\n", url);
+ trace("put_href(%s)...\n", wine_dbgstr_w(url));
doc = get_document(unk);
@@ -3204,7 +3187,7 @@ static void test_put_href(IWebBrowser2 *unk, const char *url)
dwl_flags = DWL_FROM_PUT_HREF;
- str = a2bstr(current_url = url);
+ str = SysAllocString(current_url = url);
is_first_load = FALSE;
hres = IHTMLLocation_put_href(location, str);
@@ -3220,7 +3203,7 @@ static void test_put_href(IWebBrowser2 *unk, const char *url)
test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE);
}
-static void test_go_back(IWebBrowser2 *wb, const char *back_url, int back_enable, int forward_enable, int forward_todo)
+static void test_go_back(IWebBrowser2 *wb, const WCHAR *back_url, int back_enable, int forward_enable, int forward_todo)
{
HRESULT hres;
@@ -3262,7 +3245,7 @@ static void test_go_back(IWebBrowser2 *wb, const char *back_url, int back_enable
CLEAR_CALLED(Invoke_PROPERTYCHANGE); /* called by IE11 */
}
-static void test_go_forward(IWebBrowser2 *wb, const char *forward_url, int back_enable, int forward_enable)
+static void test_go_forward(IWebBrowser2 *wb, const WCHAR *forward_url, int back_enable, int forward_enable)
{
HRESULT hres;
@@ -3456,7 +3439,7 @@ static void test_TranslateAccelerator(IWebBrowser2 *unk)
{5, 5}
};
- test_Navigate2(unk, "about:blank");
+ test_Navigate2(unk, L"about:blank");
hres = IWebBrowser2_QueryInterface(unk, &IID_IOleInPlaceActiveObject, (void**)&pao);
ok(hres == S_OK, "Got 0x%08x\n", hres);
@@ -3749,14 +3732,14 @@ static void test_WebBrowser(DWORD flags, BOOL do_close)
test_ready_state(READYSTATE_UNINITIALIZED, BUSY_FAIL);
test_ClassInfo(webbrowser);
test_EnumVerbs(webbrowser);
- test_LocationURL(webbrowser, "");
+ test_LocationURL(webbrowser, L"");
test_ConnectionPoint(webbrowser, TRUE);
test_ClientSite(webbrowser, &ClientSite, !do_download);
test_Extent(webbrowser);
test_wb_funcs(webbrowser, TRUE);
test_DoVerb(webbrowser);
test_olecmd(webbrowser, FALSE);
- test_Navigate2(webbrowser, "about:blank");
+ test_Navigate2(webbrowser, L"about:blank");
test_QueryStatusWB(webbrowser, TRUE);
if(do_download) {
@@ -3766,14 +3749,14 @@ static void test_WebBrowser(DWORD flags, BOOL do_close)
test_olecmd(webbrowser, TRUE);
doc = get_document(webbrowser);
- test_put_href(webbrowser, "about:test");
+ test_put_href(webbrowser, L"about:test");
test_download(DWL_FROM_PUT_HREF);
doc2 = get_document(webbrowser);
ok(doc == doc2, "doc != doc2\n");
IHTMLDocument2_Release(doc2);
trace("Navigate2 repeated...\n");
- test_Navigate2(webbrowser, "about:blank");
+ test_Navigate2(webbrowser, L"about:blank");
test_download(DWL_EXPECT_BEFORE_NAVIGATE);
doc2 = get_document(webbrowser);
ok(doc == doc2, "doc != doc2\n");
@@ -3783,7 +3766,7 @@ static void test_WebBrowser(DWORD flags, BOOL do_close)
if(!do_close) {
trace("Navigate2 http URL...\n");
test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE);
- test_Navigate2(webbrowser, "http://test.winehq.org/tests/hello.html");
+ test_Navigate2(webbrowser, L"http://test.winehq.org/tests/hello.html");
nav_back_todo = TRUE;
test_download(DWL_EXPECT_BEFORE_NAVIGATE|DWL_HTTP);
nav_back_todo = FALSE;
@@ -3792,31 +3775,31 @@ static void test_WebBrowser(DWORD flags, BOOL do_close)
test_Refresh(webbrowser, TRUE);
trace("put_href http URL...\n");
- test_put_href(webbrowser, "http://test.winehq.org/tests/winehq_snapshot/");
+ test_put_href(webbrowser, L"http://test.winehq.org/tests/winehq_snapshot/");
test_download(DWL_FROM_PUT_HREF|DWL_HTTP|DWL_BACK_ENABLE);
trace("GoBack...\n");
nav_back_todo = TRUE;
- test_go_back(webbrowser, "http://test.winehq.org/tests/hello.html", 0, 0, 1);
+ test_go_back(webbrowser, L"http://test.winehq.org/tests/hello.html", 0, 0, 1);
test_download(DWL_FROM_GOBACK|DWL_HTTP);
nav_back_todo = FALSE;
trace("GoForward...\n");
- test_go_forward(webbrowser, "http://test.winehq.org/tests/winehq_snapshot/", -1, 0);
+ test_go_forward(webbrowser, L"http://test.winehq.org/tests/winehq_snapshot/", -1, 0);
test_download(DWL_FROM_GOFORWARD|DWL_HTTP);
trace("GoBack...\n");
nav_back_todo = TRUE;
- test_go_back(webbrowser, "http://test.winehq.org/tests/hello.html", 0, -1, 0);
+ test_go_back(webbrowser, L"http://test.winehq.org/tests/hello.html", 0, -1, 0);
test_download(DWL_FROM_GOBACK|DWL_HTTP);
nav_back_todo = FALSE;
trace("GoForward...\n");
- test_go_forward(webbrowser, "http://test.winehq.org/tests/winehq_snapshot/", -1, 0);
+ test_go_forward(webbrowser, L"http://test.winehq.org/tests/winehq_snapshot/", -1, 0);
test_download(DWL_FROM_GOFORWARD|DWL_HTTP);
}else {
trace("Navigate2 repeated with the same URL...\n");
- test_Navigate2(webbrowser, "about:blank");
+ test_Navigate2(webbrowser, L"about:blank");
test_download(DWL_EXPECT_BEFORE_NAVIGATE);
}
@@ -3882,7 +3865,7 @@ static void test_WebBrowser_slim_container(void)
test_ConnectionPoint(webbrowser, TRUE);
test_ClientSite(webbrowser, &ClientSite, TRUE);
test_DoVerb(webbrowser);
- test_Navigate2(webbrowser, "about:blank");
+ test_Navigate2(webbrowser, L"about:blank");
/* Tests of interest */
test_QueryStatusWB(webbrowser, TRUE);
@@ -3969,13 +3952,13 @@ static void test_FileProtocol(void)
IWebBrowser2 *webbrowser;
HANDLE file;
ULONG ref;
- char file_path[MAX_PATH];
- char file_url[MAX_PATH] = "File://";
+ WCHAR file_path[MAX_PATH];
+ WCHAR file_url[MAX_PATH] = L"File://";
- static const char test_file[] = "wine_test.html";
+ static const WCHAR test_file[] = L"wine_test.html";
- GetTempPathA(MAX_PATH, file_path);
- strcat(file_path, test_file);
+ GetTempPathW(MAX_PATH, file_path);
+ lstrcatW(file_path, test_file);
webbrowser = create_webbrowser();
if(!webbrowser)
@@ -3983,16 +3966,15 @@ static void test_FileProtocol(void)
init_test(webbrowser, 0);
- file = CreateFileA(file_path, GENERIC_WRITE, 0, NULL,
- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ file = CreateFileW(file_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if(file == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS){
ok(0, "CreateFile failed\n");
return;
}
CloseHandle(file);
- GetLongPathNameA(file_path, file_path, sizeof(file_path));
- strcat(file_url, file_path);
+ GetLongPathNameW(file_path, file_path, sizeof(file_path));
+ lstrcatW(file_url, file_path);
test_ConnectionPoint(webbrowser, TRUE);
test_ClientSite(webbrowser, &ClientSite, TRUE);
@@ -4004,7 +3986,7 @@ static void test_FileProtocol(void)
ok(ref == 0, "ref=%u, expected 0\n", ref);
if(file != INVALID_HANDLE_VALUE)
- DeleteFileA(file_path);
+ DeleteFileW(file_path);
}
static HRESULT WINAPI sink_QueryInterface( IAdviseSink *iface, REFIID riid, void **obj)
--
2.24.1
2
1