This is necessary for mshtml's navigator userAgent to work properly, since some apps expect it.
The second argument seems to be output pointer that gets allocated (by CoTaskMemAlloc, or something compatible with it), but the first argument seems to be a pointer to an unknown struct, which makes it almost impossible to guess reliably what it does by just inspecting its behavior...
Thankfully, it seems only the first DWORD field is necessary for this. Changing it returns the user agent for that given mode, if the rest is zeros.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/urlmon/session.c | 40 +++++++++++++++++++++++++++ dlls/urlmon/tests/misc.c | 57 +++++++++++++++++++++++++++++++++++++++ dlls/urlmon/urlmon.spec | 2 +- dlls/urlmon/urlmon_main.c | 10 ------- 4 files changed, 98 insertions(+), 11 deletions(-)
diff --git a/dlls/urlmon/session.c b/dlls/urlmon/session.c index 052444d..e5dd26c 100644 --- a/dlls/urlmon/session.c +++ b/dlls/urlmon/session.c @@ -504,6 +504,7 @@ static BOOL get_url_encoding(HKEY root, DWORD *encoding) }
static LPWSTR user_agent; +static BOOL user_agent_set;
static size_t obtain_user_agent(unsigned int version, WCHAR *ret, size_t size) { @@ -710,6 +711,7 @@ HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBuf
heap_free(user_agent); user_agent = new_user_agent; + user_agent_set = TRUE; update_user_agent(user_agent);
LeaveCriticalSection(&session_cs); @@ -748,6 +750,44 @@ HRESULT WINAPI ObtainUserAgentString(DWORD option, char *ret, DWORD *ret_size) return hres; }
+/*********************************************************************** + * MapBrowserEmulationModeToUserAgent (URLMON.445) + * Undocumented, added in IE8 + */ +HRESULT WINAPI MapBrowserEmulationModeToUserAgent(const void *arg, WCHAR **ret) +{ + DWORD size, version; + const WCHAR *ua; + WCHAR buf[1024]; + + TRACE("%p %p: semi-stub\n", arg, ret); + + if(user_agent_set) { + /* Native ignores first arg if custom user agent has been set, doesn't crash even if NULL */ + size = (wcslen(user_agent) + 1) * sizeof(WCHAR); + ua = user_agent; + }else { + *ret = NULL; + + /* First arg seems to be a pointer to a structure of unknown size, and crashes + if it's too small (or filled with arbitrary values from the stack). For our + purposes, we only check first field which seems to be the requested version. */ + version = *(DWORD*)arg; + if(version == 5) + version = 7; + if(version < 7 || version > 11) + return E_FAIL; + + size = obtain_user_agent(version, buf, ARRAY_SIZE(buf)) * sizeof(WCHAR); + ua = buf; + } + + if(!(*ret = CoTaskMemAlloc(size))) + return E_OUTOFMEMORY; + memcpy(*ret, ua, size); + return S_OK; +} + void free_session(void) { name_space *ns_iter, *ns_last; diff --git a/dlls/urlmon/tests/misc.c b/dlls/urlmon/tests/misc.c index 0575a43..c67b1d5 100644 --- a/dlls/urlmon/tests/misc.c +++ b/dlls/urlmon/tests/misc.c @@ -83,6 +83,7 @@ static HRESULT (WINAPI *pCompareSecurityIds)(BYTE*,DWORD,BYTE*,DWORD,DWORD); static HRESULT (WINAPI *pCoInternetIsFeatureEnabled)(INTERNETFEATURELIST,DWORD); static HRESULT (WINAPI *pCoInternetSetFeatureEnabled)(INTERNETFEATURELIST,DWORD,BOOL); static HRESULT (WINAPI *pIEInstallScope)(DWORD*); +static HRESULT (WINAPI *pMapBrowserEmulationModeToUserAgent)(const void*,WCHAR**);
static WCHAR *a2co(const char *str) { @@ -2721,6 +2722,59 @@ static void test_bsc_marshaling(void) TerminateThread(thread, 0); }
+static void test_MapBrowserEmulationModeToUserAgent(BOOL custom_ua) +{ + /* Undocumented structure of unknown size, crashes if it's too small (with arbitrary values from stack) */ + struct + { + DWORD version; + char unknown[252]; + } arg; + static char test_str[] = "test"; + const char *custom_ua_msg = ""; + HRESULT hres; + unsigned i; + WCHAR *ua; + + if(!pMapBrowserEmulationModeToUserAgent) { + win_skip("MapBrowserEmulationModeToUserAgent not available\n"); + return; + } + memset(&arg, 0, sizeof(arg)); + + if(custom_ua) { + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, test_str, sizeof(test_str), 0); + ok(hres == S_OK, "UrlMkSetSessionOption failed: %08lx\n", hres); + custom_ua_msg = " (with custom ua)"; + } + + for(i = 0; i < 12; i++) { + arg.version = i; + ua = (WCHAR*)0xdeadbeef; + hres = pMapBrowserEmulationModeToUserAgent(&arg, &ua); + ok(hres == (i == 5 || i >= 7 || custom_ua ? S_OK : E_FAIL), + "[%u] MapBrowserEmulationModeToUserAgent%s returned %08lx\n", i, custom_ua_msg, hres); + if(hres != S_OK) + ok(ua == NULL, "[%u] ua%s = %p\n", i, custom_ua_msg, ua); + else { + char buf[1024]; + DWORD size = sizeof(buf); + WCHAR *ua2; + + if(custom_ua) + ua2 = a2co(test_str); + else { + hres = pObtainUserAgentString(i, buf, &size); + ok(hres == S_OK, "[%u] ObtainUserAgentString%s failed: %08lx\n", i, custom_ua_msg, hres); + ua2 = a2co(buf); + } + ok(!lstrcmpW(ua, ua2), "[%u] ua%s = %s, expected %s\n", i, custom_ua_msg, wine_dbgstr_w(ua), wine_dbgstr_w(ua2)); + CoTaskMemFree(ua2); + CoTaskMemFree(ua); + } + } +} + START_TEST(misc) { HMODULE hurlmon; @@ -2745,6 +2799,7 @@ START_TEST(misc) pCoInternetIsFeatureEnabled = (void*) GetProcAddress(hurlmon, "CoInternetIsFeatureEnabled"); pCoInternetSetFeatureEnabled = (void*) GetProcAddress(hurlmon, "CoInternetSetFeatureEnabled"); pIEInstallScope = (void*) GetProcAddress(hurlmon, "IEInstallScope"); + pMapBrowserEmulationModeToUserAgent = (void*) GetProcAddress(hurlmon, (const char*)445);
if (!pCoInternetCompareUrl || !pCoInternetGetSecurityUrl || !pCoInternetGetSession || !pCoInternetParseUrl || !pCompareSecurityIds) { @@ -2757,6 +2812,7 @@ START_TEST(misc) if(argc <= 2 || strcmp(argv[2], "internet_features")) { register_protocols();
+ test_MapBrowserEmulationModeToUserAgent(FALSE); test_CreateFormatEnum(); test_RegisterFormatEnumerator(); test_CoInternetParseUrl(); @@ -2773,6 +2829,7 @@ START_TEST(misc) test_MkParseDisplayNameEx(); test_IsValidURL(); test_bsc_marshaling(); + test_MapBrowserEmulationModeToUserAgent(TRUE); }
test_internet_features(); diff --git a/dlls/urlmon/urlmon.spec b/dlls/urlmon/urlmon.spec index ea3cd38..2fda69e 100644 --- a/dlls/urlmon/urlmon.spec +++ b/dlls/urlmon/urlmon.spec @@ -110,6 +110,6 @@ 410 stdcall @(long long) LogSqmBits 423 stdcall @(long long long long) LogSqmUXCommandOffsetInternal 444 stdcall @(long long long) MapUriToBrowserEmulationState -445 stdcall @(long long) MapBrowserEmulationModeToUserAgent +445 stdcall @(ptr ptr) MapBrowserEmulationModeToUserAgent 446 stdcall @(long) CoInternetGetBrowserProfile 455 stdcall @() FlushUrlmonZonesCache diff --git a/dlls/urlmon/urlmon_main.c b/dlls/urlmon/urlmon_main.c index b540313..56c2257 100644 --- a/dlls/urlmon/urlmon_main.c +++ b/dlls/urlmon/urlmon_main.c @@ -791,16 +791,6 @@ int WINAPI MapUriToBrowserEmulationState(DWORD unk1, DWORD unk2, DWORD unk3) return 0; }
-/*********************************************************************** - * MapBrowserEmulationModeToUserAgent (URLMON.445) - * Undocumented, added in IE8 - */ -int WINAPI MapBrowserEmulationModeToUserAgent(DWORD unk1, DWORD unk2) -{ - FIXME("stub: %ld %ld\n", unk1, unk2); - return 0; -} - /*********************************************************************** * CoInternetGetBrowserProfile (URLMON.446) * Undocumented, added in IE8
This uses the undocumented MapBrowserEmulationModeToUserAgent and only the first field of the unknown struct, but it is enough for this purpose. It is important for some apps (e.g. FFXIV Launcher) which expects it to work like this.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/omnavigator.c | 67 ++++++++++++++++++++------------------- dlls/mshtml/tests/dom.c | 51 +++++++++++++++++++++++++++++ dlls/urlmon/urlmon.spec | 2 +- 3 files changed, 87 insertions(+), 33 deletions(-)
diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 0a2a6bb..9962cc2 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -1162,77 +1162,80 @@ static HRESULT WINAPI OmNavigator_get_appName(IOmNavigator *iface, BSTR *p) return S_OK; }
-static unsigned int get_ua_version(OmNavigator *navigator) +/* undocumented, added in IE8 */ +extern HRESULT WINAPI MapBrowserEmulationModeToUserAgent(const void*,WCHAR**); + +/* Retrieves allocated user agent via CoTaskMemAlloc */ +static HRESULT get_user_agent(OmNavigator *navigator, WCHAR **user_agent) { + DWORD version; + switch(dispex_compat_mode(&navigator->dispex)) { case COMPAT_MODE_QUIRKS: case COMPAT_MODE_IE5: case COMPAT_MODE_IE7: - return 7; + version = 7; + break; case COMPAT_MODE_IE8: - return 8; + version = 8; + break; case COMPAT_MODE_IE9: - return 9; + version = 9; + break; case COMPAT_MODE_IE10: - return 10; + version = 10; + break; case COMPAT_MODE_IE11: - return 11; + version = 11; + break; + default: + assert(0); + return E_FAIL; } - assert(0); - return 0; + return MapBrowserEmulationModeToUserAgent(&version, user_agent); }
static HRESULT WINAPI OmNavigator_get_appVersion(IOmNavigator *iface, BSTR *p) { OmNavigator *This = impl_from_IOmNavigator(iface); - - char user_agent[512]; - DWORD size; + WCHAR *user_agent; + unsigned len; HRESULT hres; const unsigned skip_prefix = 8; /* strlen("Mozilla/") */
TRACE("(%p)->(%p)\n", This, p);
- size = sizeof(user_agent); - hres = ObtainUserAgentString(get_ua_version(This), user_agent, &size); + hres = get_user_agent(This, &user_agent); if(FAILED(hres)) return hres; + len = wcslen(user_agent);
- if(size <= skip_prefix) { + if(len < skip_prefix) { + CoTaskMemFree(user_agent); *p = NULL; return S_OK; }
- size = MultiByteToWideChar(CP_ACP, 0, user_agent + skip_prefix, -1, NULL, 0); - *p = SysAllocStringLen(NULL, size-1); - if(!*p) - return E_OUTOFMEMORY; - - MultiByteToWideChar(CP_ACP, 0, user_agent + skip_prefix, -1, *p, size); - return S_OK; + *p = SysAllocStringLen(user_agent + skip_prefix, len - skip_prefix); + CoTaskMemFree(user_agent); + return *p ? S_OK : E_OUTOFMEMORY; }
static HRESULT WINAPI OmNavigator_get_userAgent(IOmNavigator *iface, BSTR *p) { OmNavigator *This = impl_from_IOmNavigator(iface); - char user_agent[512]; - DWORD size; + WCHAR *user_agent; HRESULT hres;
TRACE("(%p)->(%p)\n", This, p);
- size = sizeof(user_agent); - hres = ObtainUserAgentString(get_ua_version(This), user_agent, &size); + hres = get_user_agent(This, &user_agent); if(FAILED(hres)) return hres;
- size = MultiByteToWideChar(CP_ACP, 0, user_agent, -1, NULL, 0); - *p = SysAllocStringLen(NULL, size-1); - if(!*p) - return E_OUTOFMEMORY; - - MultiByteToWideChar(CP_ACP, 0, user_agent, -1, *p, size); - return S_OK; + *p = SysAllocString(user_agent); + CoTaskMemFree(user_agent); + return *p ? S_OK : E_OUTOFMEMORY; }
static HRESULT WINAPI OmNavigator_javaEnabled(IOmNavigator *iface, VARIANT_BOOL *enabled) diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index b66073f..4af0e9b 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -6479,6 +6479,11 @@ static void test_navigator(IHTMLDocument2 *doc) ok(!lstrcmpW(bstr, buf+8), "appVersion returned %s, expected "%s"\n", wine_dbgstr_w(bstr), wine_dbgstr_w(buf+8)); SysFreeString(bstr);
+ hres = IOmNavigator_get_userAgent(navigator, &bstr); + ok(hres == S_OK, "get_userAgent failed: %08lx\n", hres); + ok(!lstrcmpW(bstr, buf), "userAgent returned %s, expected %s\n", wine_dbgstr_w(bstr), wine_dbgstr_w(buf)); + SysFreeString(bstr); + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, buf, lstrlenW(buf), 0); ok(hres == S_OK, "UrlMkSetSessionOption failed: %08lx\n", hres);
@@ -11294,6 +11299,42 @@ static void test_quirks_mode(void) "</html>", test_document_mode); }
+static void test_custom_user_agent(IHTMLDocument2 *doc) +{ + static const WCHAR ua[] = L"1234567890xxxABC"; + static char ua_ascii[] = "1234567890xxxABC"; + IOmNavigator *navigator; + IHTMLWindow2 *window; + HRESULT hres; + BSTR bstr; + + /* Set it only first time, to test it doesn't get reset on compat mode change */ + if(compat_mode == COMPAT_NONE) { + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, ua_ascii, sizeof(ua_ascii), 0); + ok(hres == S_OK, "UrlMkSetSessionOption failed: %08lx\n", hres); + } + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "parentWidnow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_navigator(window, &navigator); + ok(hres == S_OK, "get_navigator failed: %08lx\n", hres); + ok(navigator != NULL, "navigator == NULL\n"); + IHTMLWindow2_Release(window); + + hres = IOmNavigator_get_appVersion(navigator, &bstr); + ok(hres == S_OK, "get_appVersion failed: %08lx\n", hres); + ok(!lstrcmpW(bstr, ua+8), "appVersion returned %s, expected %s\n", wine_dbgstr_w(bstr), wine_dbgstr_w(ua+8)); + SysFreeString(bstr); + + hres = IOmNavigator_get_userAgent(navigator, &bstr); + ok(hres == S_OK, "get_userAgent failed: %08lx\n", hres); + ok(!lstrcmpW(bstr, ua), "userAgent returned %s, expected %s\n", wine_dbgstr_w(bstr), wine_dbgstr_w(ua)); + SysFreeString(bstr); + + IOmNavigator_Release(navigator); +} + static void check_ie(void) { IHTMLDocument2 *doc; @@ -11356,6 +11397,16 @@ START_TEST(dom)
test_quirks_mode();
+ /* Run this last since it messes with the process-wide user agent */ + if (winetest_interactive || ! is_ie_hardened()) { + run_domtest(doc_blank, test_custom_user_agent); + if(is_ie9plus) { + compat_mode = COMPAT_IE9; + run_domtest(doc_blank_ie9, test_custom_user_agent); + compat_mode = COMPAT_NONE; + } + } + DestroyWindow(container_hwnd); CoUninitialize(); } diff --git a/dlls/urlmon/urlmon.spec b/dlls/urlmon/urlmon.spec index 2fda69e..8725c8c 100644 --- a/dlls/urlmon/urlmon.spec +++ b/dlls/urlmon/urlmon.spec @@ -110,6 +110,6 @@ 410 stdcall @(long long) LogSqmBits 423 stdcall @(long long long long) LogSqmUXCommandOffsetInternal 444 stdcall @(long long long) MapUriToBrowserEmulationState -445 stdcall @(ptr ptr) MapBrowserEmulationModeToUserAgent +445 stdcall -noname MapBrowserEmulationModeToUserAgent(ptr ptr) 446 stdcall @(long) CoInternetGetBrowserProfile 455 stdcall @() FlushUrlmonZonesCache
Signed-off-by: Jacek Caban jacek@codeweavers.com
ObtainUserAgentString returns the currently set (custom) user agent unless the version requested is a valid one (7, 8, ... 11, or 7 | UAS_EXACTLEGACY), in which case it uses that version to build the user agent.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/urlmon/session.c | 14 +++++++++----- dlls/urlmon/tests/misc.c | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/dlls/urlmon/session.c b/dlls/urlmon/session.c index e5dd26c..d533ee8 100644 --- a/dlls/urlmon/session.c +++ b/dlls/urlmon/session.c @@ -508,9 +508,9 @@ static BOOL user_agent_set;
static size_t obtain_user_agent(unsigned int version, WCHAR *ret, size_t size) { + BOOL is_wow, quirks = FALSE, use_current = FALSE; OSVERSIONINFOW info = {sizeof(info)}; const WCHAR *os_type, *is_nt; - BOOL is_wow, quirks = FALSE; DWORD res; size_t len = 0; HKEY key; @@ -519,17 +519,18 @@ static size_t obtain_user_agent(unsigned int version, WCHAR *ret, size_t size) version &= ~UAS_EXACTLEGACY; if(version == 7) quirks = TRUE; - else + else { + use_current = TRUE; version = 7; - }else if(version < 7) { - version = 7; + } } + if(version > 11) { FIXME("Unsupported version %u\n", version); version = 11; }
- if(version < 7 || (version == 7 && !quirks)) { + if(version < 7 || use_current) { EnterCriticalSection(&session_cs); if(user_agent) { len = wcslen(user_agent) + 1; @@ -539,6 +540,9 @@ static size_t obtain_user_agent(unsigned int version, WCHAR *ret, size_t size) if(len) return len; }
+ if(version < 7) + version = 7; + swprintf(ret, size, L"Mozilla/%s (", version < 9 ? L"4.0" : L"5.0"); len = lstrlenW(ret); if(version < 11) { diff --git a/dlls/urlmon/tests/misc.c b/dlls/urlmon/tests/misc.c index c67b1d5..638dcae 100644 --- a/dlls/urlmon/tests/misc.c +++ b/dlls/urlmon/tests/misc.c @@ -1635,6 +1635,26 @@ static void test_user_agent(void) ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08lx\n", hres); ok(size == sizeof(test_str) && !memcmp(str2, test_str, sizeof(test_str)), "wrong user agent\n");
+ for(i = 0; i < 12; i++) { + size = sizeof(ua); + hres = pObtainUserAgentString(i, ua, &size); + ok(hres == S_OK, "[%u] ObtainUserAgentString failed: %08lx\n", i, hres); + ok(size == strlen(ua) + 1, "[%u] unexpected size %lu, expected %Iu\n", i, size, strlen(ua) + 1); + if(i >= 7) + ok(strcmp(ua, test_str), "[%u] unexpected UA, did not expect "test"\n", i); + else + ok(!strcmp(ua, test_str), "[%u] unexpected UA %s, expected "test"\n", i, wine_dbgstr_a(ua)); + + size = sizeof(ua); + hres = pObtainUserAgentString(i | UAS_EXACTLEGACY, ua, &size); + ok(hres == S_OK, "[%u] ObtainUserAgentString failed: %08lx\n", i, hres); + ok(size == strlen(ua) + 1, "[%u] unexpected size %lu, expected %Iu\n", i, size, strlen(ua) + 1); + if(i == 7) + ok(strcmp(ua, test_str), "[%u] unexpected UA, did not expect "test"\n", i); + else + ok(!strcmp(ua, test_str), "[%u] unexpected UA %s, expected "test"\n", i, wine_dbgstr_a(ua)); + } + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, test2_str, sizeof(test2_str), 0); ok(hres == S_OK, "UrlMkSetSessionOption failed: %08lx\n", hres);
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Tested in the next patch (we use the test_own_data_prop_desc helper to avoid redundancy, which also checks enumerable).
dlls/jscript/dispex.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index ef13e29..32265d3 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2546,6 +2546,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl switch(prop->type) { case PROP_BUILTIN: case PROP_JSVAL: + case PROP_IDX: desc->mask |= PROPF_WRITABLE; desc->explicit_value = TRUE; if(!flags_only) {
Signed-off-by: Jacek Caban jacek@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 17 ++++++++++++++++- dlls/mshtml/tests/es5.js | 28 +++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 32265d3..6ee02a0 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -285,7 +285,10 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, for(ptr = name; is_digit(*ptr) && idx < 0x10000; ptr++) idx = idx*10 + (*ptr-'0'); if(!*ptr && idx < This->builtin_info->idx_length(This)) { - prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? PROPF_WRITABLE : 0); + unsigned flags = PROPF_ENUMERABLE; + if(This->builtin_info->idx_put) + flags |= PROPF_WRITABLE; + prop = alloc_prop(This, name, PROP_IDX, flags); if(!prop) return E_OUTOFMEMORY;
@@ -2444,6 +2447,18 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty HRESULT hres;
if(id == DISPID_STARTENUM) { + if(obj->builtin_info->idx_length) { + unsigned i = 0, len = obj->builtin_info->idx_length(obj); + WCHAR name[12]; + + for(i = 0; i < len; i++) { + swprintf(name, ARRAY_SIZE(name), L"%d", i); + hres = find_prop_name(obj, string_hash(name), name, &iter); + if(FAILED(hres)) + return hres; + } + } + if (enum_type == JSDISP_ENUM_ALL) { hres = fill_protrefs(obj); if(FAILED(hres)) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 0339d9b..6baebbd 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -654,12 +654,38 @@ sync_test("property_definitions", function() { });
sync_test("string_idx", function() { - var s = "foobar"; + var i, s = "foobar"; ok(s[0] === "f", "s[0] = " + s[0]); ok(s[5] === "r", "s[5] = " + s[5]); ok(s[6] === undefined, "s[6] = " + s[6]); ok((delete s[0]) === false, "delete s[0] returned true"); ok((delete s[6]) === true, "delete s[6] returned false"); + s[6] = "X"; + ok(s[6] === undefined, "s[6] = " + s[6]); + + s = new String(s); + test_own_data_prop_desc(s, "0", false, true, false); + test_own_data_prop_desc(s, "1", false, true, false); + ok(!s.hasOwnProperty("6"), "'6' is a property"); + + s[7] = "X"; + ok(s[7] === "X", "s[7] = " + s[7]); + // s.hasOwnProperty("7") returns false on Win8 likely due to a bug in its js engine + + Object.defineProperty(s, "8", {writable: false, enumerable: true, configurable: true, value: "Y"}); + ok(s[8] === "Y", "s[8] = " + s[8]); + ok(s.hasOwnProperty("8"), "'8' not a property"); + + String.prototype[9] = "Z"; + ok(s[9] === "Z", "s[9] = " + s[9]); + delete String.prototype[9]; + + i = 0; + for(var idx in s) { + ok(s[idx] === "foobar XY"[idx], "enum s[" + idx + "] = " + s[idx]); + i++; + } + ok(i === 8, "enum did " + i + " iterations"); });
sync_test("string_trim", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=112361
Your paranoid android.
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w7u_adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1649694554212 expected 1649694554265"
Signed-off-by: Jacek Caban jacek@codeweavers.com
Instead of crashing.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 3 +++ dlls/jscript/tests/api.js | 2 ++ dlls/mshtml/tests/documentmode.js | 13 +++++++++++++ 3 files changed, 18 insertions(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 6ee02a0..319617b 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -560,6 +560,9 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t case PROP_BUILTIN: { jsval_t vthis;
+ if(!prop->u.p->invoke) + return JS_E_FUNCTION_EXPECTED; + if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) { WARN("%s is not a constructor\n", debugstr_w(prop->name)); return E_INVALIDARG; diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 9eaeddd..fe336d4 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2611,6 +2611,8 @@ testException(function() {delete false;}, "E_INVALID_DELETE"); testException(function() {undefined.toString();}, "E_OBJECT_EXPECTED"); testException(function() {null.toString();}, "E_OBJECT_EXPECTED"); testException(function() {RegExp.prototype.toString.call(new Object());}, "E_REGEXP_EXPECTED"); +testException(function() {/a/.lastIndex();}, "E_NOT_FUNC"); +testException(function() {"a".length();}, "E_NOT_FUNC");
testException(function() { return arguments.callee(); }, "E_STACK_OVERFLOW");
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 3f772cf..55de9b7 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1307,6 +1307,19 @@ sync_test("builtins_diffs", function() { }catch(e) { ok(e.number === 0xa1398 - 0x80000000, "RegExp.toString with non-regexp: exception = " + e.number); } + + try { + /a/.lastIndex(); + ok(false, "/a/.lastIndex(): expected exception"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "/a/.lastIndex(): exception = " + e.number); + } + try { + "a".length(); + ok(false, ""a".length(): expected exception"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, ""a".length(): exception = " + e.number); + } });
sync_test("__proto__", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=112362
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
Signed-off-by: Jacek Caban jacek@codeweavers.com