From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 337 +++++++++++++++++++++ 1 file changed, 337 insertions(+)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 972fd33e499..e648820a51a 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -6754,6 +6754,28 @@ static void set_cache_request(struct UiaCacheRequest *req, struct UiaCondition * req->automationElementMode = elem_mode; }
+static void set_property_condition(struct UiaPropertyCondition *cond, int prop_id, VARIANT *val, int flags) +{ + cond->ConditionType = ConditionType_Property; + cond->PropertyId = prop_id; + cond->Value = *val; + cond->Flags = flags; +} + +static void set_and_or_condition(struct UiaAndOrCondition *cond, int cond_type, + struct UiaCondition **conds, int cond_count) +{ + cond->ConditionType = cond_type; + cond->ppConditions = conds; + cond->cConditions = cond_count; +} + +static void set_not_condition(struct UiaNotCondition *cond, struct UiaCondition *not_cond) +{ + cond->ConditionType = ConditionType_Not; + cond->pConditions = not_cond; +} + #define MAX_NODE_PROVIDERS 4 struct node_provider_desc { DWORD pid; @@ -6896,13 +6918,42 @@ static const struct prov_method_sequence cache_req_seq3[] = { { 0 } };
+ +static const struct prov_method_sequence cache_req_seq4[] = { + { &Provider, PROV_GET_PROPERTY_VALUE }, /* Dependent upon property condition. */ + { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId. */ + { 0 } +}; + +/* Sequence for non-matching property condition. */ +static const struct prov_method_sequence cache_req_seq5[] = { + { &Provider, PROV_GET_PROPERTY_VALUE }, /* Dependent upon property condition. */ + { &Provider, PROV_GET_PROPERTY_VALUE }, /* Dependent upon property condition. */ + /* Only done on Win10v1507 and below. */ + { &Provider, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ + { 0 } +}; + +static const struct prov_method_sequence cache_req_seq6[] = { + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId. */ + /* Only done on Win10v1507 and below. */ + { &Provider, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ + { 0 } +}; + static const struct UiaCondition UiaTrueCondition = { ConditionType_True }; static const struct UiaCondition UiaFalseCondition = { ConditionType_False }; static void test_UiaGetUpdatedCache(void) { + struct Provider_prop_override prop_override; struct node_provider_desc exp_node_desc[2]; + struct UiaPropertyCondition prop_cond; + struct UiaAndOrCondition and_or_cond; LONG exp_lbound[2], exp_elems[2], i; struct UiaCacheRequest cache_req; + struct UiaCondition *cond_arr[2]; + struct UiaNotCondition not_cond; SAFEARRAY *out_req; BSTR tree_struct; HUIANODE node; @@ -7067,6 +7118,292 @@ static void test_UiaGetUpdatedCache(void) SafeArrayDestroy(out_req); SysFreeString(tree_struct);
+ /* + * ConditionType_And tests. + */ + for (i = 0; i < ARRAY_SIZE(exp_node_desc); i++) + init_node_provider_desc(&exp_node_desc[i], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider", TRUE); + cond_arr[0] = (struct UiaCondition *)&UiaTrueCondition; + cond_arr[1] = (struct UiaCondition *)&UiaTrueCondition; + set_and_or_condition(&and_or_cond, ConditionType_And, cond_arr, ARRAY_SIZE(cond_arr)); + set_cache_request(&cache_req, (struct UiaCondition *)&and_or_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + /* Equivalent to: if (1 && 1) */ + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (out_req) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(cache_req_seq1, NULL); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + cond_arr[0] = (struct UiaCondition *)&UiaTrueCondition; + cond_arr[1] = (struct UiaCondition *)&UiaFalseCondition; + set_and_or_condition(&and_or_cond, ConditionType_And, cond_arr, ARRAY_SIZE(cond_arr)); + set_cache_request(&cache_req, (struct UiaCondition *)&and_or_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + /* Equivalent to: if (1 && 0) */ + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ok_method_sequence(cache_req_seq2, NULL); + + ok(!out_req, "out_req != NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (tree_struct) + ok(!wcscmp(tree_struct, L""), "tree structure %s\n", debugstr_w(tree_struct)); + SysFreeString(tree_struct); + + /* + * ConditionType_Or tests. + */ + cond_arr[0] = (struct UiaCondition *)&UiaTrueCondition; + cond_arr[1] = (struct UiaCondition *)&UiaFalseCondition; + set_and_or_condition(&and_or_cond, ConditionType_Or, cond_arr, ARRAY_SIZE(cond_arr)); + set_cache_request(&cache_req, (struct UiaCondition *)&and_or_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + /* Equivalent to: if (1 || 0) */ + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (out_req) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(cache_req_seq1, NULL); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + cond_arr[0] = (struct UiaCondition *)&UiaFalseCondition; + cond_arr[1] = (struct UiaCondition *)&UiaFalseCondition; + set_and_or_condition(&and_or_cond, ConditionType_Or, cond_arr, ARRAY_SIZE(cond_arr)); + set_cache_request(&cache_req, (struct UiaCondition *)&and_or_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + /* Equivalent to: if (0 || 0) */ + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ok_method_sequence(cache_req_seq2, NULL); + + ok(!out_req, "out_req != NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (tree_struct) + ok(!wcscmp(tree_struct, L""), "tree structure %s\n", debugstr_w(tree_struct)); + SysFreeString(tree_struct); + + /* + * ConditionType_Not tests. + */ + set_not_condition(¬_cond, (struct UiaCondition *)&UiaFalseCondition); + set_cache_request(&cache_req, (struct UiaCondition *)¬_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + /* Equivalent to: if (!0) */ + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (out_req) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(cache_req_seq1, NULL); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + set_not_condition(¬_cond, (struct UiaCondition *)&UiaTrueCondition); + set_cache_request(&cache_req, (struct UiaCondition *)¬_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + /* Equivalent to: if (!1) */ + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ok_method_sequence(cache_req_seq2, NULL); + + ok(!out_req, "out_req != NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (tree_struct) + ok(!wcscmp(tree_struct, L""), "tree structure %s\n", debugstr_w(tree_struct)); + SysFreeString(tree_struct); + + /* + * ConditionType_Property tests. + */ + Provider.ret_invalid_prop_type = FALSE; + + /* Test UIAutomationType_IntArray property conditions. */ + if (UiaLookupId(AutomationIdentifierType_Property, &OutlineColor_Property_GUID)) + { + V_VT(&v) = VT_I4 | VT_ARRAY; + V_ARRAY(&v) = create_i4_safearray(); + set_property_condition(&prop_cond, UIA_OutlineColorPropertyId, &v, PropertyConditionFlags_None); + set_cache_request(&cache_req, (struct UiaCondition *)&prop_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (out_req) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(cache_req_seq4, NULL); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + VariantClear(&v); + + /* Same values, except we're short by one element. */ + V_VT(&v) = VT_I4 | VT_ARRAY; + V_ARRAY(&v) = SafeArrayCreateVector(VT_I4, 0, ARRAY_SIZE(uia_i4_arr_prop_val) - 1); + + for (i = 0; i < ARRAY_SIZE(uia_i4_arr_prop_val) - 1; i++) + SafeArrayPutElement(V_ARRAY(&prop_cond.Value), &i, (void *)&uia_i4_arr_prop_val[i]); + + set_property_condition(&prop_cond, UIA_OutlineColorPropertyId, &v, PropertyConditionFlags_None); + set_cache_request(&cache_req, (struct UiaCondition *)&prop_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ok_method_sequence(cache_req_seq5, NULL); + ok(!out_req, "out_req != NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (tree_struct) + ok(!wcscmp(tree_struct, L""), "tree structure %s\n", debugstr_w(tree_struct)); + SysFreeString(tree_struct); + VariantClear(&v); + } + else + win_skip("UIA_OutlineColorPropertyId unavailable, skipping property condition tests for it.\n"); + + /* UIA_RuntimeIdPropertyId comparison. */ + Provider.runtime_id[0] = 0xdeadbeef; Provider.runtime_id[1] = 0xfeedbeef; + V_VT(&v) = VT_I4 | VT_ARRAY; + V_ARRAY(&v) = SafeArrayCreateVector(VT_I4, 0, ARRAY_SIZE(Provider.runtime_id)); + for (i = 0; i < ARRAY_SIZE(Provider.runtime_id); i++) + SafeArrayPutElement(V_ARRAY(&v), &i, (void *)&Provider.runtime_id[i]); + + set_property_condition(&prop_cond, UIA_RuntimeIdPropertyId, &v, PropertyConditionFlags_None); + set_cache_request(&cache_req, (struct UiaCondition *)&prop_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (out_req) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(cache_req_seq6, NULL); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + VariantClear(&prop_cond.Value); + + /* UIAutomationType_Bool property condition tests. */ + prop_override.prop_id = UIA_IsControlElementPropertyId; + V_VT(&prop_override.val) = VT_BOOL; + V_BOOL(&prop_override.val) = VARIANT_FALSE; + Provider.prop_override = &prop_override; + Provider.prop_override_count = 1; + + V_VT(&v) = VT_BOOL; + V_BOOL(&v) = VARIANT_FALSE; + set_property_condition(&prop_cond, UIA_IsControlElementPropertyId, &v, PropertyConditionFlags_None); + set_cache_request(&cache_req, (struct UiaCondition *)&prop_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (out_req) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(cache_req_seq4, NULL); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + VariantClear(&prop_cond.Value); + + /* + * Provider now returns VARIANT_TRUE for UIA_IsControlElementPropertyId, + * conditional check will fail. + */ + prop_override.prop_id = UIA_IsControlElementPropertyId; + V_VT(&prop_override.val) = VT_BOOL; + V_BOOL(&prop_override.val) = VARIANT_TRUE; + Provider.prop_override = &prop_override; + Provider.prop_override_count = 1; + + V_VT(&v) = VT_BOOL; + V_BOOL(&v) = VARIANT_FALSE; + set_property_condition(&prop_cond, UIA_IsControlElementPropertyId, &v, PropertyConditionFlags_None); + set_cache_request(&cache_req, (struct UiaCondition *)&prop_cond, TreeScope_Element, NULL, 0, NULL, 0, + AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + + hr = UiaGetUpdatedCache(node, &cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ok_method_sequence(cache_req_seq5, NULL); + ok(!out_req, "out_req != NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + if (tree_struct) + ok(!wcscmp(tree_struct, L""), "tree structure %s\n", debugstr_w(tree_struct)); + SysFreeString(tree_struct); + VariantClear(&prop_cond.Value); + + Provider.prop_override = NULL; + Provider.prop_override_count = 0; + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);