From: Vibhav Pant vibhavp@gmail.com
--- dlls/cfgmgr32/tests/cfgmgr32.c | 115 ++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-)
diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 5841a1a8d4b..6b501cf4ea3 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2023 Mohamad Al-Jaf + * Copyright (C) 2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -859,12 +860,90 @@ static void test_DevGetObjects( void ) &bool_val, } }; + static const DEVPROP_FILTER_EXPRESSION filter_instance_id_exists = { + DEVPROP_OPERATOR_NOT_EQUALS, { { DEVPKEY_Device_InstanceId, DEVPROP_STORE_SYSTEM, NULL }, DEVPROP_TYPE_EMPTY, 0, NULL } + }; + static const DEVPROP_FILTER_EXPRESSION filter_instance_id_not_exists = { + DEVPROP_OPERATOR_EQUALS, { { DEVPKEY_Device_InstanceId, DEVPROP_STORE_SYSTEM, NULL }, DEVPROP_TYPE_EMPTY, 0, NULL } + }; + /* Test cases for filter expressions containing boolean operators. All of these filters are logically equivalent + * and should return identical objects, unless "empty" is TRUE. */ + static const struct { + const char *query; /* The query as an AQS device selector. */ + DEVPROP_FILTER_EXPRESSION expr[8]; + SIZE_T size; + BOOL empty; + } logical_op_test_cases[] = { + { + "NOT (System.Devices.InstanceId := [])", + { { DEVPROP_OPERATOR_NOT_OPEN }, filter_instance_id_not_exists, { DEVPROP_OPERATOR_NOT_CLOSE } }, + 3 + }, + { + "NOT (NOT (System.Device.InstanceId :- []))", + { { DEVPROP_OPERATOR_NOT_OPEN }, { DEVPROP_OPERATOR_NOT_OPEN }, + filter_instance_id_exists, + { DEVPROP_OPERATOR_NOT_CLOSE }, { DEVPROP_OPERATOR_NOT_CLOSE } }, + 5 + }, + { + "NOT ((System.Device.InstanceId := []) AND (System.Device.InstanceId :- []))", + { { DEVPROP_OPERATOR_NOT_OPEN }, + { DEVPROP_OPERATOR_AND_OPEN }, filter_instance_id_not_exists, filter_instance_id_exists,{ DEVPROP_OPERATOR_AND_CLOSE }, + { DEVPROP_OPERATOR_NOT_CLOSE } }, + 6 + }, + { + "NOT ((NOT (System.Device.InstanceId :- [])) AND (System.Device.InstanceId :- []))", + { { DEVPROP_OPERATOR_NOT_OPEN }, + { DEVPROP_OPERATOR_AND_OPEN }, + { DEVPROP_OPERATOR_NOT_OPEN }, filter_instance_id_exists, { DEVPROP_OPERATOR_NOT_CLOSE }, + filter_instance_id_exists, + { DEVPROP_OPERATOR_AND_CLOSE }, + { DEVPROP_OPERATOR_NOT_CLOSE } }, + 8 + }, + { + "((System.Device.InstanceId :- []) OR (System.Device.InstanceId := []))", + { { DEVPROP_OPERATOR_OR_OPEN }, filter_instance_id_exists, filter_instance_id_not_exists, { DEVPROP_OPERATOR_OR_CLOSE } }, + 4 + }, + { + "((System.Devices.InstanceId :- [] AND System.Devices.InstanceId :- []) OR System.Device.InstanceId := [])", + { { DEVPROP_OPERATOR_OR_OPEN }, + { DEVPROP_OPERATOR_AND_OPEN }, filter_instance_id_exists, filter_instance_id_exists, { DEVPROP_OPERATOR_AND_CLOSE }, + filter_instance_id_not_exists, + { DEVPROP_OPERATOR_OR_CLOSE } }, + 7 + }, + /* Filters that return empty results */ + { + "NOT (System.Devices.InstanceId :- [])", + { { DEVPROP_OPERATOR_NOT_OPEN }, filter_instance_id_exists, { DEVPROP_OPERATOR_NOT_CLOSE } }, + 3, + TRUE, + }, + { + "NOT (NOT (System.Devices.InstanceId := [] AND System.Devices.InstanceId :- []))", + { { DEVPROP_OPERATOR_NOT_OPEN }, { DEVPROP_OPERATOR_NOT_OPEN }, + { DEVPROP_OPERATOR_AND_OPEN }, filter_instance_id_not_exists, filter_instance_id_exists, { DEVPROP_OPERATOR_AND_CLOSE }, + { DEVPROP_OPERATOR_NOT_CLOSE }, { DEVPROP_OPERATOR_NOT_CLOSE } }, + 8, + TRUE, + }, + { + "(System.Devices.InstanceId := [] OR System.Devices.InstanceId := [])", + { { DEVPROP_OPERATOR_OR_OPEN }, filter_instance_id_not_exists, filter_instance_id_not_exists, { DEVPROP_OPERATOR_OR_CLOSE } }, + 4, + TRUE + } + }; DEVPROPCOMPKEY prop_iface_class = { DEVPKEY_DeviceInterface_ClassGuid, DEVPROP_STORE_SYSTEM, NULL }; DEVPROP_FILTER_EXPRESSION filters[4]; const DEV_OBJECT *objects = NULL; DEVPROPCOMPKEY prop_key = {0}; + ULONG i, len = 0, len2 = 0; HRESULT hr; - ULONG i, len = 0;
if (!pDevGetObjects || !pDevFreeObjects || !pDevFindProperty) { @@ -1158,6 +1237,40 @@ static void test_DevGetObjects( void ) pDevFreeObjects( len, objects ); bool_val = TRUE;
+ /* Get the number of objects that the filters in logical_op_test_cases should return. */ + filters[0] = filter_instance_id_exists; + len = 0; + objects = NULL; + hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagNone, 0, NULL, 1, filters, &len, &objects ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + ok( len > 0, "got len %lu\n", len ); + ok( !!objects, "got objects %p\n", objects ); + pDevFreeObjects( len, objects ); + + for (i = 0; i < ARRAY_SIZE( logical_op_test_cases ); i++ ) + { + winetest_push_context( "i=%lu (%s)", i, debugstr_a( logical_op_test_cases[i].query ) ); + + len2 = 0; + objects = NULL; + hr = pDevGetObjects( DevObjectTypeDeviceInterface, DevQueryFlagNone, 0, NULL, logical_op_test_cases[i].size, + logical_op_test_cases[i].expr, &len2, &objects ); + ok( hr == S_OK, "got hr %#lx\n", hr ); + if (logical_op_test_cases[i].empty) + { + todo_wine_if( len2 ) ok( !len2, "got len2 %lu\n", len2 ); + todo_wine_if( len2 ) ok( !objects, "got objects %p\n", objects ); + } + else + { + todo_wine_if( !len2 ) ok( len2 == len, "got len2 %lu != %lu\n", len2, len ); + todo_wine_if( !len2 ) ok( !!objects, "got objects %p\n", objects ); + } + pDevFreeObjects( len2, objects ); + + winetest_pop_context(); + } + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) { const DEV_OBJECT *objects = NULL;