From: Vibhav Pant vibhavp@gmail.com
--- dlls/structuredquery/tests/Makefile.in | 2 +- dlls/structuredquery/tests/query.c | 306 ++++++++++++++++++++++++- 2 files changed, 306 insertions(+), 2 deletions(-)
diff --git a/dlls/structuredquery/tests/Makefile.in b/dlls/structuredquery/tests/Makefile.in index 5bf2fc317b7..993410856b4 100644 --- a/dlls/structuredquery/tests/Makefile.in +++ b/dlls/structuredquery/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = structuredquery.dll -IMPORTS = ole32 oleaut32 +IMPORTS = ole32 oleaut32 propsys
SOURCES = \ query.c diff --git a/dlls/structuredquery/tests/query.c b/dlls/structuredquery/tests/query.c index 27d374331e6..b09f887703e 100644 --- a/dlls/structuredquery/tests/query.c +++ b/dlls/structuredquery/tests/query.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 Vibhav Pant + * Copyright 2024-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 @@ -19,9 +19,44 @@ #define COBJMACROS #include <initguid.h> #include <structuredquery.h> +#include <propvarutil.h>
#include <wine/test.h>
+static const char *debugstr_propvar( const PROPVARIANT *v ) +{ + if (!v) + return "(null)"; + + switch (v->vt) + { + case VT_EMPTY: + return wine_dbg_sprintf( "%p {VT_EMPTY}", v ); + case VT_NULL: + return wine_dbg_sprintf( "%p {VT_NULL}", v ); + case VT_UI4: + return wine_dbg_sprintf( "%p {VT_UI4: %ld}", v, v->ulVal ); + case VT_UI8: + return wine_dbg_sprintf( "%p {VT_UI8: %s}", v, wine_dbgstr_longlong( v->uhVal.QuadPart ) ); + case VT_I8: + return wine_dbg_sprintf( "%p {VT_I8: %s}", v, wine_dbgstr_longlong( v->hVal.QuadPart ) ); + case VT_R4: + return wine_dbg_sprintf( "%p {VT_R4: %.8e}", v, v->fltVal ); + case VT_R8: + return wine_dbg_sprintf( "%p {VT_R8: %lf}", v, v->dblVal ); + case VT_CLSID: + return wine_dbg_sprintf( "%p {VT_CLSID: %s}", v, wine_dbgstr_guid( v->puuid ) ); + case VT_LPWSTR: + return wine_dbg_sprintf( "%p {VT_LPWSTR: %s}", v, wine_dbgstr_w( v->pwszVal ) ); + case VT_BOOL: + return wine_dbg_sprintf( "%p {VT_BOOL: %d}", v, v->bVal ); + case VT_FILETIME: + return wine_dbg_sprintf( "%p {VT_FILETIME: %s}", v, wine_dbgstr_longlong( v->uhVal.QuadPart ) ); + default: + return wine_dbg_sprintf( "%p {vt %#x}", v, v->vt ); + } +} + void test_IQueryParser( void ) { HRESULT hr; @@ -38,11 +73,280 @@ void test_IQueryParser( void ) IQueryParser_Release( parser ); }
+void test_parser( IQueryParser *parser ) +{ + WCHAR *guid = wcsdup( L"{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" ); + struct test_case + { + const WCHAR *query_str; + struct + { + const WCHAR *prop_name; + CONDITION_OPERATION op; + PROPVARIANT propvar; + } leaf_conds[2]; + CONDITION_TYPE cond_type; + DWORD subconditions; + } test_cases[] = { + { + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#False", + {{L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_FALSE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:-System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_NOTEQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:≠System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_NOTEQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:NOT System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_NOTEQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.CompatibleIds:~={92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}", + {{L"System.Devices.CompatibleIds", COP_VALUE_CONTAINS, {.vt = VT_LPWSTR, .pwszVal = guid}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.CompatibleIds:~!{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}", + {{L"System.Devices.CompatibleIds", COP_VALUE_NOTCONTAINS, {.vt = VT_LPWSTR, .pwszVal = guid}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceClassGuid:="{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" OR " + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True", + { + {L"System.Devices.InterfaceClassGuid", COP_EQUAL, {.vt = VT_LPWSTR, .pwszVal = guid}}, + {L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}, + }, + CT_OR_CONDITION, + 2 + }, + { + L"System.Devices.InterfaceClassGuid:="{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" AND " + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True", + { + {L"System.Devices.InterfaceClassGuid", COP_EQUAL, {.vt = VT_LPWSTR, .pwszVal = guid}}, + {L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}, + }, + CT_AND_CONDITION, + 2 + }, + { + L"System.Devices.InterfaceClassGuid:="{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" AND " + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#False", + { + {L"System.Devices.InterfaceClassGuid", COP_EQUAL, {.vt = VT_LPWSTR, .pwszVal = guid}}, + {L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_FALSE}}, + }, + CT_AND_CONDITION, + 2 + }, + }; + DWORD i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++ ) + { + const WCHAR *query = test_cases[i].query_str; + IEnumUnknown *conditions; + IQuerySolution *solution; + IConditionFactory *factory; + CONDITION_TYPE cond_type; + ICondition *cond, *cond2; + + IEntity *entity; + HRESULT hr; + DWORD j; + + winetest_push_context( "test_cases[%lu]", i ); + hr = IQueryParser_Parse( parser, query, NULL, &solution ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "Parse failed.\n" ); + winetest_pop_context(); + continue; + } + + hr = IQuerySolution_GetQuery( solution, &cond, &entity ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "GetQuery failed.\n" ); + winetest_pop_context(); + IQuerySolution_Release( solution ); + continue; + } + hr = IQuerySolution_QueryInterface( solution, &IID_IConditionFactory, (void *)&factory ); + IQuerySolution_Release( solution ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "QueryInterface failed.\n" ); + winetest_pop_context(); + continue; + } + + hr = IConditionFactory_Resolve( factory, cond, SQRO_DONT_RESOLVE_DATETIME | SQRO_ADD_VALUE_TYPE_FOR_PLAIN_VALUES, + NULL, &cond2 ); + ICondition_Release( cond ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip("Resolve failed.\n"); + winetest_pop_context(); + continue; + } + + hr = ICondition_GetConditionType( cond2, &cond_type ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( cond_type == test_cases[i].cond_type, "%d != %d\n", cond_type, test_cases[i].cond_type ); + + if (cond_type == CT_LEAF_CONDITION) + { + LPWSTR prop_name; + CONDITION_OPERATION op; + PROPVARIANT propvar; + + PropVariantInit( &propvar ); + hr = ICondition_GetComparisonInfo( cond2, &prop_name, &op, &propvar ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( !wcsicmp( prop_name, test_cases[i].leaf_conds[0].prop_name ), "%s != %s\n", debugstr_w( prop_name ), + debugstr_w( test_cases[i].leaf_conds[0].prop_name ) ); + ok( op == test_cases[i].leaf_conds[0].op, "%d != %d\n", op, test_cases[i].leaf_conds[0].op ); + + ok( !PropVariantCompareEx( &propvar, &test_cases[i].leaf_conds[0].propvar, PVCU_DEFAULT, PVCF_DEFAULT ), + "%s != %s\n", debugstr_propvar( &propvar ), debugstr_propvar( &test_cases[i].leaf_conds[0].propvar ) ); + PropVariantClear( &propvar ); + CoTaskMemFree( prop_name ); + winetest_pop_context(); + ICondition_Release( cond2 ); + IEntity_Release( entity ); + continue; + } + + hr = ICondition_GetSubConditions( cond2, &IID_IEnumUnknown, (void *)&conditions ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "GetSubConditions failed.\n" ); + ICondition_Release( cond2 ); + IEntity_Release( entity ); + winetest_pop_context(); + continue; + } + + for (j = 0; j < test_cases[i].subconditions; j++) + { + IUnknown *out; + ICondition *leaf; + ULONG fetched; + LPWSTR prop_name; + CONDITION_OPERATION op; + PROPVARIANT propvar; + + winetest_push_context( "leaf_conds[%lu]", j ); + hr = IEnumUnknown_Next( conditions, 1, &out, &fetched ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (hr != S_OK) + { + skip( "Next failed.\n" ); + winetest_pop_context(); + break; + } + + hr = IUnknown_QueryInterface( out, &IID_ICondition, (void *)&leaf ); + ok( hr == S_OK, "got %#lx\n", hr ); + IUnknown_Release( out ); + if (FAILED( hr )) + { + skip( "QueryInterface failed.\n" ); + winetest_pop_context(); + break; + } + + hr = ICondition_GetConditionType( leaf, &cond_type ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( cond_type == CT_LEAF_CONDITION, "%d != %d\n", cond_type, CT_LEAF_CONDITION ); + + PropVariantInit( &propvar ); + hr = ICondition_GetComparisonInfo( leaf, &prop_name, &op, &propvar ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( !wcsicmp( prop_name, test_cases[i].leaf_conds[j].prop_name ), "%s != %s\n", debugstr_w( prop_name ), + debugstr_w( test_cases[i].leaf_conds[j].prop_name ) ); + ok( op == test_cases[i].leaf_conds[j].op, "%d != %d\n", op, test_cases[i].leaf_conds[j].op ); + + ok( !PropVariantCompareEx( &propvar, &test_cases[i].leaf_conds[j].propvar, PVCU_DEFAULT, PVCF_DEFAULT ), + "%s != %s\n", debugstr_propvar( &propvar ), debugstr_propvar( &test_cases[i].leaf_conds[j].propvar ) ); + winetest_pop_context(); + PropVariantClear( &propvar ); + ICondition_Release( leaf ); + CoTaskMemFree( prop_name ); + } + + winetest_pop_context(); + IEnumUnknown_Release( conditions ); + ICondition_Release( cond2 ); + IEntity_Release( entity ); + } + + free( guid ); +} + +void test_IQueryParserManager( void ) +{ + HRESULT hr; + IQueryParserManager *manager = NULL; + IQueryParser *parser; + + hr = CoCreateInstance( &CLSID_QueryParserManager, NULL, CLSCTX_INPROC, &IID_IQueryParserManager, + (void **)&manager ); + todo_wine ok( hr == S_OK, "got %#lx\n", hr ); + if (!manager) + { + skip( "Could not create IQueryParserManager instance.\n" ); + return; + } + + hr = IQueryParserManager_CreateLoadedParser( manager, L"SystemIndex", LANG_SYSTEM_DEFAULT, &IID_IQueryParser, + (void *)&parser ); + todo_wine ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "CreateLoadedParser failed.\n" ); + goto done; + } + + todo_wine test_parser( parser ); + IQueryParser_Release( parser ); +done: + IQueryParserManager_Release( manager ); +} + START_TEST(query) { CoInitializeEx( NULL, COINIT_MULTITHREADED );
test_IQueryParser(); + test_IQueryParserManager();
CoUninitialize(); }