mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-01 21:13:38 +00:00
jscript: Implement fdexNameCaseInsensitive flag handling.
Despite common sense, native doesn't seem to look for exact match first; it simply case-insensitively compares the props and returns as soon as it finds one. This is also reliant on implementation details in case the object has multiple props with same case-insensitive names, e.g. an object having `Foo` prop, with `foo` prop on its prototype, can still find `Foo` even if you look up `foo` instead (which matches exactly on the prototype). Which is not always reliable, sometimes it finds the prototype first. Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
parent
015491ab32
commit
7be0cffa06
|
@ -128,28 +128,24 @@ static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
|
|||
return prop->flags;
|
||||
}
|
||||
|
||||
static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name)
|
||||
static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens)
|
||||
{
|
||||
int min = 0, max, i, r;
|
||||
int min = 0, max = This->builtin_info->props_cnt-1, i, r;
|
||||
unsigned version;
|
||||
|
||||
if(case_insens) {
|
||||
for(i = min; i <= max; i++)
|
||||
if(!wcsicmp(name, This->builtin_info->props[i].name))
|
||||
goto found;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
max = This->builtin_info->props_cnt-1;
|
||||
while(min <= max) {
|
||||
i = (min+max)/2;
|
||||
|
||||
r = wcscmp(name, This->builtin_info->props[i].name);
|
||||
if(!r) {
|
||||
/* Skip prop if it's available only in higher compatibility mode. */
|
||||
unsigned version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK)
|
||||
>> PROPF_VERSION_SHIFT;
|
||||
if(version && version > This->ctx->version)
|
||||
return NULL;
|
||||
|
||||
/* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
|
||||
if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode)
|
||||
return NULL;
|
||||
|
||||
return This->builtin_info->props + i;
|
||||
}
|
||||
if(!r)
|
||||
goto found;
|
||||
|
||||
if(r < 0)
|
||||
max = i-1;
|
||||
|
@ -158,6 +154,18 @@ static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name
|
|||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
/* Skip prop if it's available only in higher compatibility mode. */
|
||||
version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK) >> PROPF_VERSION_SHIFT;
|
||||
if(version && version > This->ctx->version)
|
||||
return NULL;
|
||||
|
||||
/* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
|
||||
if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode)
|
||||
return NULL;
|
||||
|
||||
return This->builtin_info->props + i;
|
||||
}
|
||||
|
||||
static inline unsigned string_hash(const WCHAR *name)
|
||||
|
@ -237,7 +245,7 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref
|
|||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
|
||||
static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret)
|
||||
{
|
||||
const builtin_prop_t *builtin;
|
||||
unsigned bucket, pos, prev = ~0;
|
||||
|
@ -247,7 +255,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
|
|||
bucket = get_props_idx(This, hash);
|
||||
pos = This->props[bucket].bucket_head;
|
||||
while(pos != ~0) {
|
||||
if(!wcscmp(name, This->props[pos].name)) {
|
||||
if(case_insens ? !wcsicmp(name, This->props[pos].name) : !wcscmp(name, This->props[pos].name)) {
|
||||
if(prev != ~0) {
|
||||
This->props[prev].bucket_next = This->props[pos].bucket_next;
|
||||
This->props[pos].bucket_next = This->props[bucket].bucket_head;
|
||||
|
@ -262,7 +270,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
|
|||
pos = This->props[pos].bucket_next;
|
||||
}
|
||||
|
||||
builtin = find_builtin_prop(This, name);
|
||||
builtin = find_builtin_prop(This, name, case_insens);
|
||||
if(builtin) {
|
||||
unsigned flags = builtin->flags;
|
||||
if(flags & PROPF_METHOD) {
|
||||
|
@ -272,7 +280,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
prop = alloc_prop(This, name, PROP_JSVAL, (flags & PROPF_ALL) | PROPF_WRITABLE | PROPF_CONFIGURABLE);
|
||||
prop = alloc_prop(This, builtin->name, PROP_JSVAL, (flags & PROPF_ALL) | PROPF_WRITABLE | PROPF_CONFIGURABLE);
|
||||
if(!prop) {
|
||||
jsdisp_release(obj);
|
||||
return E_OUTOFMEMORY;
|
||||
|
@ -285,7 +293,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
|
|||
}else if(builtin->setter)
|
||||
flags |= PROPF_WRITABLE;
|
||||
flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE;
|
||||
prop = alloc_prop(This, name, PROP_BUILTIN, flags);
|
||||
prop = alloc_prop(This, builtin->name, PROP_BUILTIN, flags);
|
||||
if(!prop)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
|
@ -318,12 +326,12 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
|
||||
static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret)
|
||||
{
|
||||
dispex_prop_t *prop, *del=NULL;
|
||||
HRESULT hres;
|
||||
|
||||
hres = find_prop_name(This, hash, name, &prop);
|
||||
hres = find_prop_name(This, hash, name, case_insens, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(prop && prop->type==PROP_DELETED) {
|
||||
|
@ -335,7 +343,7 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n
|
|||
}
|
||||
|
||||
if(This->prototype) {
|
||||
hres = find_prop_name_prot(This->prototype, hash, name, &prop);
|
||||
hres = find_prop_name_prot(This->prototype, hash, name, case_insens, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(prop && prop->type != PROP_DELETED) {
|
||||
|
@ -358,12 +366,12 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *n
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, dispex_prop_t **ret)
|
||||
static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, dispex_prop_t **ret)
|
||||
{
|
||||
dispex_prop_t *prop;
|
||||
HRESULT hres;
|
||||
|
||||
hres = find_prop_name_prot(This, string_hash(name), name, &prop);
|
||||
hres = find_prop_name_prot(This, string_hash(name), name, case_insens, &prop);
|
||||
if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
|
||||
TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags);
|
||||
|
||||
|
@ -613,7 +621,7 @@ static HRESULT fill_protrefs(jsdisp_t *This)
|
|||
fill_protrefs(This->prototype);
|
||||
|
||||
for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
|
||||
hres = find_prop_name(This, iter->hash, iter->name, &prop);
|
||||
hres = find_prop_name(This, iter->hash, iter->name, FALSE, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(!prop || prop->type==PROP_DELETED) {
|
||||
|
@ -1532,7 +1540,7 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW
|
|||
|
||||
TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid);
|
||||
|
||||
if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
|
||||
if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
|
||||
FIXME("Unsupported grfdex %lx\n", grfdex);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
@ -1678,10 +1686,10 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst
|
|||
|
||||
TRACE("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex);
|
||||
|
||||
if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
|
||||
if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
|
||||
FIXME("Unsupported grfdex %lx\n", grfdex);
|
||||
|
||||
hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
|
||||
hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(!prop) {
|
||||
|
@ -1902,7 +1910,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built
|
|||
dispex_prop_t *prop;
|
||||
HRESULT hres;
|
||||
|
||||
hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", &prop);
|
||||
hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, &prop);
|
||||
if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
|
||||
jsval_t val;
|
||||
|
||||
|
@ -1941,9 +1949,9 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *
|
|||
|
||||
if(jsdisp->extensible && (flags & fdexNameEnsure))
|
||||
hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE,
|
||||
&prop);
|
||||
flags & fdexNameCaseInsensitive, &prop);
|
||||
else
|
||||
hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
|
||||
hres = find_prop_name_prot(jsdisp, string_hash(name), name, flags & fdexNameCaseInsensitive, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
@ -1996,7 +2004,7 @@ HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned
|
|||
dispex_prop_t *prop;
|
||||
HRESULT hres;
|
||||
|
||||
hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
|
||||
hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
@ -2227,9 +2235,9 @@ HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw
|
|||
HRESULT hres;
|
||||
|
||||
if(obj->extensible)
|
||||
hres = ensure_prop_name(obj, name, flags, &prop);
|
||||
hres = ensure_prop_name(obj, name, flags, FALSE, &prop);
|
||||
else
|
||||
hres = find_prop_name(obj, string_hash(name), name, &prop);
|
||||
hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
if(!prop || (prop->type == PROP_DELETED && !obj->extensible))
|
||||
|
@ -2330,7 +2338,7 @@ HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
|
|||
dispex_prop_t *prop;
|
||||
HRESULT hres;
|
||||
|
||||
hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
|
||||
hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
@ -2350,7 +2358,7 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
|
|||
|
||||
swprintf(name, ARRAY_SIZE(name), L"%d", idx);
|
||||
|
||||
hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
|
||||
hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
@ -2407,7 +2415,7 @@ HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
|
|||
|
||||
swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
|
||||
|
||||
hres = find_prop_name(obj, string_hash(buf), buf, &prop);
|
||||
hres = find_prop_name(obj, string_hash(buf), buf, FALSE, &prop);
|
||||
if(FAILED(hres) || !prop)
|
||||
return hres;
|
||||
|
||||
|
@ -2465,7 +2473,7 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty
|
|||
|
||||
for(i = 0; i < len; i++) {
|
||||
swprintf(name, ARRAY_SIZE(name), L"%d", i);
|
||||
hres = find_prop_name(obj, string_hash(name), name, &iter);
|
||||
hres = find_prop_name(obj, string_hash(name), name, FALSE, &iter);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
@ -2514,7 +2522,7 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL
|
|||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop);
|
||||
hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &prop);
|
||||
if(prop) {
|
||||
hres = delete_prop(prop, ret);
|
||||
}else {
|
||||
|
@ -2561,7 +2569,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl
|
|||
dispex_prop_t *prop;
|
||||
HRESULT hres;
|
||||
|
||||
hres = find_prop_name(obj, string_hash(name), name, &prop);
|
||||
hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
@ -2605,7 +2613,7 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t
|
|||
dispex_prop_t *prop;
|
||||
HRESULT hres;
|
||||
|
||||
hres = find_prop_name(obj, string_hash(name), name, &prop);
|
||||
hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
|
|
|
@ -930,6 +930,124 @@ static void test_aggregation(void)
|
|||
ok(!unk || broken(unk != NULL), "unk = %p\n", unk);
|
||||
}
|
||||
|
||||
static void test_case_sens(void)
|
||||
{
|
||||
static const WCHAR *const names[] = { L"abc", L"foo", L"bar", L"mAth", L"evaL" };
|
||||
DISPPARAMS dp = { NULL, NULL, 0, 0 };
|
||||
IActiveScriptParse *parser;
|
||||
IActiveScript *script;
|
||||
EXCEPINFO ei = { 0 };
|
||||
IDispatchEx *disp;
|
||||
DISPID id, id2;
|
||||
unsigned i;
|
||||
HRESULT hr;
|
||||
VARIANT v;
|
||||
BSTR bstr;
|
||||
|
||||
script = create_jscript();
|
||||
|
||||
hr = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser);
|
||||
ok(hr == S_OK, "Could not get IActiveScriptParse iface: %08lx\n", hr);
|
||||
|
||||
SET_EXPECT(GetLCID);
|
||||
hr = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
|
||||
ok(hr == S_OK, "SetScriptSite failed: %08lx\n", hr);
|
||||
CHECK_CALLED(GetLCID);
|
||||
|
||||
SET_EXPECT(OnStateChange_INITIALIZED);
|
||||
hr = IActiveScriptParse_InitNew(parser);
|
||||
ok(hr == S_OK, "InitNew failed: %08lx\n", hr);
|
||||
CHECK_CALLED(OnStateChange_INITIALIZED);
|
||||
|
||||
SET_EXPECT(OnStateChange_CONNECTED);
|
||||
hr = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED);
|
||||
ok(hr == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08lx\n", hr);
|
||||
CHECK_CALLED(OnStateChange_CONNECTED);
|
||||
|
||||
parse_script(parser, L"var aBc; var abC; function Foo() { }\nFoo.prototype.foo = 13; var Bar = new Foo(); Bar.Foo = 42;");
|
||||
disp = get_script_dispatch(script, NULL);
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(names); i++) {
|
||||
bstr = SysAllocString(names[i]);
|
||||
hr = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
|
||||
ok(hr == DISP_E_UNKNOWNNAME, "GetIDsOfNames(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hr, DISP_E_UNKNOWNNAME);
|
||||
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, 0, &id);
|
||||
ok(hr == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hr, DISP_E_UNKNOWNNAME);
|
||||
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id);
|
||||
ok(hr == S_OK, "GetDispID(%s) with fdexNameCaseInsensitive failed: %08lx\n", debugstr_w(bstr), hr);
|
||||
ok(id > 0, "Unexpected DISPID for %s: %ld\n", debugstr_w(bstr), id);
|
||||
SysFreeString(bstr);
|
||||
}
|
||||
|
||||
get_disp_id(disp, L"Bar", S_OK, &id);
|
||||
hr = IDispatchEx_InvokeEx(disp, id, 0, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL);
|
||||
ok(hr == S_OK, "InvokeEx failed: %08lx\n", hr);
|
||||
ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v));
|
||||
ok(V_DISPATCH(&v) != NULL, "V_DISPATCH(v) = NULL\n");
|
||||
IDispatchEx_Release(disp);
|
||||
|
||||
hr = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IDispatchEx, (void**)&disp);
|
||||
ok(hr == S_OK, "Could not get IDispatchEx iface: %08lx\n", hr);
|
||||
VariantClear(&v);
|
||||
|
||||
bstr = SysAllocString(L"foo");
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseSensitive, &id);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
|
||||
/* Native picks one "arbitrarily" here, depending how it's laid out, so can't compare exact id */
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
|
||||
hr = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id2);
|
||||
ok(hr == S_OK, "GetIDsOfNames failed: %08lx\n", hr);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hr = IDispatchEx_DeleteMemberByName(disp, bstr, fdexNameCaseInsensitive);
|
||||
ok(hr == S_OK, "DeleteMemberByName failed: %08lx\n", hr);
|
||||
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
ok(id == id2, "id != id2\n");
|
||||
SysFreeString(bstr);
|
||||
|
||||
bstr = SysAllocString(L"fOo");
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameEnsure, &id2);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
ok(id != id2, "id == id2\n");
|
||||
|
||||
hr = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2);
|
||||
ok(hr == S_OK, "GetDispID failed: %08lx\n", hr);
|
||||
SysFreeString(bstr);
|
||||
|
||||
IDispatchEx_Release(disp);
|
||||
IActiveScriptParse_Release(parser);
|
||||
|
||||
SET_EXPECT(OnStateChange_DISCONNECTED);
|
||||
SET_EXPECT(OnStateChange_INITIALIZED);
|
||||
SET_EXPECT(OnStateChange_CLOSED);
|
||||
hr = IActiveScript_Close(script);
|
||||
ok(hr == S_OK, "Close failed: %08lx\n", hr);
|
||||
CHECK_CALLED(OnStateChange_DISCONNECTED);
|
||||
CHECK_CALLED(OnStateChange_INITIALIZED);
|
||||
CHECK_CALLED(OnStateChange_CLOSED);
|
||||
|
||||
IActiveScript_Release(script);
|
||||
}
|
||||
|
||||
static void test_param_ids(void)
|
||||
{
|
||||
static const WCHAR *const names1[] = { L"test", L"c", L"foo", L"b", L"a" };
|
||||
|
@ -2324,6 +2442,7 @@ START_TEST(jscript)
|
|||
test_jscript2();
|
||||
test_jscript_uninitializing();
|
||||
test_aggregation();
|
||||
test_case_sens();
|
||||
test_param_ids();
|
||||
test_code_persistence();
|
||||
test_named_items();
|
||||
|
|
|
@ -33,6 +33,18 @@ var JS_E_WRONG_THIS = 0x800a13fc;
|
|||
|
||||
var tests = [];
|
||||
|
||||
sync_test("script vars", function() {
|
||||
function foo() { }
|
||||
foo.prototype.foo = 13;
|
||||
var obj = new foo();
|
||||
obj.Foo = 42;
|
||||
obj.aBc = 1;
|
||||
obj.abC = 2;
|
||||
obj.Bar = 3;
|
||||
document.body.foobar = 42;
|
||||
external.testVars(document.body, obj);
|
||||
});
|
||||
|
||||
sync_test("date_now", function() {
|
||||
var now = Date.now();
|
||||
var time = (new Date()).getTime();
|
||||
|
|
|
@ -155,6 +155,7 @@ DEFINE_EXPECT(GetTypeInfo);
|
|||
#define DISPID_EXTERNAL_NULL_DISP 0x300008
|
||||
#define DISPID_EXTERNAL_IS_ENGLISH 0x300009
|
||||
#define DISPID_EXTERNAL_LIST_SEP 0x30000A
|
||||
#define DISPID_EXTERNAL_TEST_VARS 0x30000B
|
||||
|
||||
static const GUID CLSID_TestScript =
|
||||
{0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}};
|
||||
|
@ -198,6 +199,95 @@ static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
|
|||
return res == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static void test_script_vars(unsigned argc, VARIANTARG *argv)
|
||||
{
|
||||
static const WCHAR *const jsobj_names[] = { L"abc", L"foO", L"bar", L"TostRing", L"hasownpropERty" };
|
||||
IHTMLBodyElement *body;
|
||||
IDispatchEx *disp;
|
||||
DISPID id, id2;
|
||||
HRESULT hres;
|
||||
unsigned i;
|
||||
BSTR bstr;
|
||||
|
||||
ok(argc == 2, "argc = %d\n", argc);
|
||||
ok(V_VT(&argv[0]) == VT_DISPATCH, "VT = %d\n", V_VT(&argv[0]));
|
||||
ok(V_VT(&argv[1]) == VT_DISPATCH, "VT = %d\n", V_VT(&argv[1]));
|
||||
|
||||
/* JS object disp */
|
||||
hres = IDispatch_QueryInterface(V_DISPATCH(&argv[0]), &IID_IDispatchEx, (void**)&disp);
|
||||
ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres);
|
||||
|
||||
hres = IDispatchEx_QueryInterface(disp, &IID_IHTMLBodyElement, (void**)&body);
|
||||
ok(hres == E_NOINTERFACE, "Got IHTMLBodyElement iface on JS object? %08lx\n", hres);
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(jsobj_names); i++) {
|
||||
bstr = SysAllocString(jsobj_names[i]);
|
||||
hres = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
|
||||
ok(hres == DISP_E_UNKNOWNNAME, "GetIDsOfNames(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hres, DISP_E_UNKNOWNNAME);
|
||||
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, 0, &id);
|
||||
ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hres, DISP_E_UNKNOWNNAME);
|
||||
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id);
|
||||
ok(hres == S_OK, "GetDispID(%s) with fdexNameCaseInsensitive failed: %08lx\n", debugstr_w(bstr), hres);
|
||||
ok(id > 0, "Unexpected DISPID for %s: %ld\n", debugstr_w(bstr), id);
|
||||
SysFreeString(bstr);
|
||||
}
|
||||
|
||||
bstr = SysAllocString(L"foo");
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseSensitive, &id);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
|
||||
/* Native picks one "arbitrarily" here, depending how it's laid out, so can't compare exact id */
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
|
||||
hres = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id2);
|
||||
ok(hres == S_OK, "GetIDsOfNames failed: %08lx\n", hres);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hres = IDispatchEx_DeleteMemberByName(disp, bstr, fdexNameCaseInsensitive);
|
||||
ok(hres == S_OK, "DeleteMemberByName failed: %08lx\n", hres);
|
||||
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
ok(id == id2, "id != id2\n");
|
||||
SysFreeString(bstr);
|
||||
|
||||
bstr = SysAllocString(L"fOo");
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id2);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
ok(id == id2, "id != id2\n");
|
||||
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameEnsure, &id2);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
ok(id != id2, "id == id2\n");
|
||||
|
||||
hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive | fdexNameEnsure, &id2);
|
||||
ok(hres == S_OK, "GetDispID failed: %08lx\n", hres);
|
||||
SysFreeString(bstr);
|
||||
|
||||
IDispatchEx_Release(disp);
|
||||
|
||||
/* Body element disp */
|
||||
hres = IDispatch_QueryInterface(V_DISPATCH(&argv[1]), &IID_IDispatchEx, (void**)&disp);
|
||||
ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres);
|
||||
|
||||
hres = IDispatchEx_QueryInterface(disp, &IID_IHTMLBodyElement, (void**)&body);
|
||||
ok(hres == S_OK, "Could not get IHTMLBodyElement iface: %08lx\n", hres);
|
||||
IHTMLBodyElement_Release(body);
|
||||
|
||||
IDispatchEx_Release(disp);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
|
||||
REFIID riid, void**ppv)
|
||||
{
|
||||
|
@ -609,6 +699,10 @@ static HRESULT WINAPI externalDisp_GetDispID(IDispatchEx *iface, BSTR bstrName,
|
|||
*pid = DISPID_EXTERNAL_LIST_SEP;
|
||||
return S_OK;
|
||||
}
|
||||
if(!lstrcmpW(bstrName, L"testVars")) {
|
||||
*pid = DISPID_EXTERNAL_TEST_VARS;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName));
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
|
@ -833,6 +927,15 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
case DISPID_EXTERNAL_TEST_VARS:
|
||||
ok(pdp != NULL, "pdp == NULL\n");
|
||||
ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
|
||||
ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
|
||||
ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
|
||||
ok(pei != NULL, "pei == NULL\n");
|
||||
test_script_vars(pdp->cArgs, pdp->rgvarg);
|
||||
return S_OK;
|
||||
|
||||
default:
|
||||
ok(0, "unexpected call\n");
|
||||
return E_NOTIMPL;
|
||||
|
|
Loading…
Reference in a new issue