From: Vibhav Pant vibhavp@gmail.com
--- configure.ac | 1 + dlls/bluetoothapis/tests/Makefile.in | 5 + dlls/bluetoothapis/tests/sdp.c | 516 +++++++++++++++++++++++++++ 3 files changed, 522 insertions(+) create mode 100644 dlls/bluetoothapis/tests/Makefile.in create mode 100644 dlls/bluetoothapis/tests/sdp.c
diff --git a/configure.ac b/configure.ac index 2d841d0d496..6890e452c6f 100644 --- a/configure.ac +++ b/configure.ac @@ -2468,6 +2468,7 @@ WINE_CONFIG_MAKEFILE(dlls/bcrypt) WINE_CONFIG_MAKEFILE(dlls/bcrypt/tests) WINE_CONFIG_MAKEFILE(dlls/bcryptprimitives) WINE_CONFIG_MAKEFILE(dlls/bluetoothapis) +WINE_CONFIG_MAKEFILE(dlls/bluetoothapis/tests) WINE_CONFIG_MAKEFILE(dlls/browseui) WINE_CONFIG_MAKEFILE(dlls/browseui/tests) WINE_CONFIG_MAKEFILE(dlls/bthprops.cpl) diff --git a/dlls/bluetoothapis/tests/Makefile.in b/dlls/bluetoothapis/tests/Makefile.in new file mode 100644 index 00000000000..c2e8bc0377a --- /dev/null +++ b/dlls/bluetoothapis/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = bluetoothapis.dll +IMPORTS = bluetoothapis + +SOURCES = \ + sdp.c diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c new file mode 100644 index 00000000000..ea223aeaa40 --- /dev/null +++ b/dlls/bluetoothapis/tests/sdp.c @@ -0,0 +1,516 @@ +/* Tests for bluetoothapis.dll's SDP API + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include <stdarg.h> +#include <windef.h> +#include <winbase.h> + +#include "bthsdpdef.h" +#include "bluetoothapis.h" + +#include "wine/test.h" + +#define XX(v) case (v): return #v + +static inline const char *debugstr_SDP_TYPE( SDP_TYPE t ) +{ + switch (t) + { + XX( SDP_TYPE_NIL ); + XX( SDP_TYPE_UINT ); + XX( SDP_TYPE_INT ); + XX( SDP_TYPE_UUID ); + XX( SDP_TYPE_STRING ); + XX( SDP_TYPE_BOOLEAN ); + XX( SDP_TYPE_SEQUENCE ); + XX( SDP_TYPE_ALTERNATIVE ); + XX( SDP_TYPE_URL ); + XX( SDP_TYPE_CONTAINER ); + default: + return wine_dbg_sprintf( "(unknown %#x)", t ); + } +} + +static inline const char *debugstr_SDP_SPECIFIC_TYPE( SDP_SPECIFICTYPE st ) +{ + switch (st) + { + XX( SDP_ST_NONE ); + XX( SDP_ST_UINT8 ); + XX( SDP_ST_UINT16 ); + XX( SDP_ST_UINT32 ); + XX( SDP_ST_UINT64 ); + XX( SDP_ST_UINT128 ); + XX( SDP_ST_INT8 ); + XX( SDP_ST_INT16 ); + XX( SDP_ST_INT32 ); + XX( SDP_ST_INT64 ); + XX( SDP_ST_INT128 ); + XX( SDP_ST_UUID16 ); + XX( SDP_ST_UUID128 ); + default: + return wine_dbg_sprintf( "(unknown %#x)", st ); + } +} + +#undef XX + +static inline const char *debugstr_sdp_element_data_unknown( const SDP_ELEMENT_DATA *data ) +{ + return wine_dbg_sprintf( "{%s %s %s}", debugstr_SDP_TYPE( data->type ), + debugstr_SDP_SPECIFIC_TYPE( data->specificType ), + debugstr_an( (const char *)&data->data, sizeof( data->data ) ) ); +} + +static const char *debugstr_SDP_ELEMENT_DATA( const SDP_ELEMENT_DATA *data ) +{ + switch (data->type) + { + case SDP_TYPE_UINT: + { + switch (data->specificType) + { + case SDP_ST_UINT8: + return wine_dbg_sprintf( "{.uint8=%u}", data->data.uint8 ); + case SDP_ST_UINT16: + return wine_dbg_sprintf( "{.uint16=%u}", data->data.uint16 ); + case SDP_ST_UINT32: + return wine_dbg_sprintf( "{.uint32=%lu}", data->data.uint32 ); + case SDP_ST_UINT64: + return wine_dbg_sprintf( "{.uint64=%llu}", data->data.uint64 ); + case SDP_ST_UINT128: + return wine_dbg_sprintf( "{.uint128={%llu %llu}}", data->data.uint128.LowPart, + data->data.uint128.HighPart ); + default: + return debugstr_sdp_element_data_unknown( data ); + } + } + case SDP_TYPE_INT: + switch (data->specificType) + { + case SDP_ST_INT8: + return wine_dbg_sprintf( "{.int8=%d}", data->data.int8 ); + case SDP_ST_INT16: + return wine_dbg_sprintf( "{.int16=%d}", data->data.int16 ); + case SDP_ST_INT32: + return wine_dbg_sprintf( "{.int32=%ld}", data->data.int32 ); + case SDP_ST_INT64: + return wine_dbg_sprintf( "{.int64=%lld}", data->data.int64 ); + case SDP_ST_INT128: + return wine_dbg_sprintf( "{.int128={%lld %lld}}", + data->data.int128.LowPart, + data->data.int128.HighPart ); + default: + return debugstr_sdp_element_data_unknown( data ); + } + case SDP_TYPE_UUID: + switch (data->specificType) + { + case SDP_ST_UUID16: + return wine_dbg_sprintf( "{.uuid16=%#02x}", data->data.uuid16 ); + case SDP_ST_UUID32: + return wine_dbg_sprintf( "{.uuid32=%#04lx}", data->data.uuid32 ); + case SDP_ST_UUID128: + return wine_dbg_sprintf( "{.uuid128=%s}", + debugstr_guid( &data->data.uuid128 ) ); + default: + return debugstr_sdp_element_data_unknown( data ); + } + case SDP_TYPE_BOOLEAN: + if (data->specificType == SDP_ST_NONE) + return wine_dbg_sprintf( "{.bool=%u}", data->data.booleanVal ); + else + return debugstr_sdp_element_data_unknown( data ); + case SDP_TYPE_STRING: + return wine_dbg_sprintf( "{.string={%p %lu}}", data->data.string.value, + data->data.string.length ); + case SDP_TYPE_URL: + return wine_dbg_sprintf( "{.url={%p %lu}}", data->data.url.value, + data->data.url.length ); + case SDP_TYPE_SEQUENCE: + return wine_dbg_sprintf( "{.sequence={%p %lu}}", data->data.sequence.value, + data->data.sequence.length ); + case SDP_TYPE_ALTERNATIVE: + return wine_dbg_sprintf( "{.alternative={%p %lu}}", data->data.alternative.value, + data->data.alternative.length ); + default: + return debugstr_sdp_element_data_unknown( data ); + } +} + +static void test_BluetoothSdpGetElementData( BYTE *stream, SIZE_T size, DWORD error, + const SDP_ELEMENT_DATA *sdp_data ) +{ + DWORD ret; + SDP_ELEMENT_DATA result = {0}; + + ret = BluetoothSdpGetElementData( stream, size, &result ); + ok( ret == error, "Expected BluetoothSdpGetElementData to return %ld, got %ld.\n", error, ret ); + if (error == ERROR_SUCCESS) + { + ok( result.type == sdp_data->type, "Expected SDP_TYPE %s, got %s.\n", + debugstr_SDP_TYPE( sdp_data->type ), debugstr_SDP_TYPE( result.type ) ); + ok( result.specificType == sdp_data->specificType, + "Expected SDP_SPECIFIC_TYPE %s, got %s.\n", + debugstr_SDP_SPECIFIC_TYPE( sdp_data->specificType ), + debugstr_SDP_SPECIFIC_TYPE( result.specificType ) ); + ok( !memcmp( &sdp_data->data, &result.data, sizeof( result.data ) ), "Expected %s, got %s.\n", + debugstr_SDP_ELEMENT_DATA( sdp_data ), debugstr_SDP_ELEMENT_DATA( &result ) ); + + } +} + +#define TEST_CASE_NAME( n ) ("%s %d"), __func__, (int)(n) + +static void test_BluetoothSdpGetElementData_invalid( void ) +{ + SDP_ELEMENT_DATA data; + BYTE stream[] = {0b00000000}; + DWORD ret; + + ret = BluetoothSdpGetElementData( NULL, 10, &data ); + ok( ret == ERROR_INVALID_PARAMETER, + "Expected BluetoothSdpGetElementData to return %d, got %ld.\n", ERROR_INVALID_PARAMETER, + ret ); + + ret = BluetoothSdpGetElementData( stream, 1, NULL ); + ok( ret == ERROR_INVALID_PARAMETER, + "Expected BluetoothSdpGetElementData to return %d, got %ld.\n", ERROR_INVALID_PARAMETER, + ret ); + + ret = BluetoothSdpGetElementData( stream, 0, &data ); + ok( ret == ERROR_INVALID_PARAMETER, + "Expected BluetoothSdpGetElementData to return %d, got %ld.\n", ERROR_INVALID_PARAMETER, + ret ); + + ret = BluetoothSdpGetElementData( NULL, 0, NULL ); + ok( ret == ERROR_INVALID_PARAMETER, + "Expected BluetoothSdpGetElementData to return %d, got %ld.\n", ERROR_INVALID_PARAMETER, + ret ); +} + +static void test_BluetoothSdpGetElementData_nil( void ) +{ + static struct + { + BYTE data_elem; + DWORD error; + SDP_ELEMENT_DATA data; + } test_cases[] = { + {0b00000000, ERROR_SUCCESS, {.type = SDP_TYPE_NIL, .specificType = SDP_ST_NONE }}, + {0b00000001, ERROR_INVALID_PARAMETER}, + {0b00000011, ERROR_INVALID_PARAMETER}, + {0b00000100, ERROR_INVALID_PARAMETER}, + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + winetest_push_context(TEST_CASE_NAME( i+1 )); + test_BluetoothSdpGetElementData( &test_cases[i].data_elem, 1, test_cases[i].error, + &test_cases[i].data ); + winetest_pop_context(); + } +} + +#define SDP_SIZEDESC_1_BYTE 0 +#define SDP_SIZEDESC_2_BYTES 1 +#define SDP_SIZEDESC_4_BYTES 2 +#define SDP_SIZEDESC_8_BYTES 3 +#define SDP_SIZEDESC_16_BYTES 4 +#define SDP_SIZEDESC_NEXT_UINT8 5 +#define SDP_SIZEDESC_NEXT_UINT16 6 +#define SDP_SIZEDESC_NEXT_UINT32 7 + +#define SDP_DATA_ELEM_TYPE_DESC(t,s) ((t) << 3 | SDP_SIZEDESC_##s) + +#define SDP_DEF_TYPE(n, t, s) const static BYTE SDP_TYPEDISC_##n = SDP_DATA_ELEM_TYPE_DESC(SDP_TYPE_##t, s) +#define SDP_DEF_INTEGRAL( w, s ) \ + SDP_DEF_TYPE( INT##w, INT, s ); \ + SDP_DEF_TYPE( UINT##w, UINT, s); + +SDP_DEF_INTEGRAL( 8, 1_BYTE ); +SDP_DEF_INTEGRAL( 16, 2_BYTES ); +SDP_DEF_INTEGRAL( 32, 4_BYTES ); +SDP_DEF_INTEGRAL( 64, 8_BYTES ); +SDP_DEF_INTEGRAL( 128, 16_BYTES ); + +SDP_DEF_TYPE( STR8, STRING, NEXT_UINT8 ); +SDP_DEF_TYPE( STR16, STRING, NEXT_UINT16 ); +SDP_DEF_TYPE( STR32, STRING, NEXT_UINT32 ); + +SDP_DEF_TYPE( SEQ8, SEQUENCE, NEXT_UINT8 ); +SDP_DEF_TYPE( SEQ16, SEQUENCE, NEXT_UINT16 ); +SDP_DEF_TYPE( SEQ32, SEQUENCE, NEXT_UINT32 ); + +static void test_BluetoothSdpGetElementData_ints( void ) +{ + static struct + { + BYTE data_elem[17]; + SIZE_T size; + DWORD error; + SDP_ELEMENT_DATA data; + } test_cases[] = { + { + {SDP_TYPEDISC_INT8, 0xde}, + 2, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT8, {.int8 = 0xde}} + }, + { + {SDP_TYPEDISC_UINT8, 0xde}, + 2, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + }, + { + {SDP_TYPEDISC_INT16, 0xde, 0xad}, + 3, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT16, {.int16 = 0xdead}}, + }, + { + {SDP_TYPEDISC_UINT16, 0xde, 0xad }, + 3, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT16, {.uint16 = 0xdead}}, + }, + { + {SDP_TYPEDISC_INT32, 0xde, 0xad, 0xbe, 0xef}, + 5, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT32, {.int32 = 0xdeadbeef}}, + }, + { + {SDP_TYPEDISC_UINT32, 0xde, 0xad, 0xbe, 0xef}, + 5, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT32, {.uint32 = 0xdeadbeef}}, + }, + { + {SDP_TYPEDISC_INT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT64, {.int64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPEDISC_UINT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT64, {.uint64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPEDISC_INT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT64, {.int64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPEDISC_UINT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT64, {.uint64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPEDISC_INT128, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef }, + 17, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT128, {.int128 = {0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef}}}, + }, + { + {SDP_TYPEDISC_UINT128, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 17, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT128, {.uint128 = {0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef}}}, + } + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + winetest_push_context( TEST_CASE_NAME( i+1 ) ); + test_BluetoothSdpGetElementData( test_cases[i].data_elem, test_cases[i].size, + test_cases[i].error, &test_cases[i].data ); + winetest_pop_context(); + } +} + +static void test_BluetoothSdpGetElementData_str( void ) +{ + static struct { + BYTE stream[11]; + SIZE_T size; + DWORD error; + SDP_ELEMENT_DATA data; + const char *string; + } test_cases[] = { + { + {SDP_TYPEDISC_STR8, 0x06, 'f', 'o', 'o', 'b', 'a', 'r'}, + 8, + ERROR_SUCCESS, + {SDP_TYPE_STRING, SDP_ST_NONE, .data = {.string = {&test_cases[0].stream[2], 6}}}, + "foobar", + }, + { + {SDP_TYPEDISC_STR16, 0x00, 0x06, 'f', 'o', 'o', 'b', 'a', 'r'}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_STRING, SDP_ST_NONE, .data = {.string = {&test_cases[1].stream[3], 6}}}, + "foobar", + }, + { + {SDP_TYPEDISC_STR32, 0x00, 0x00, 0x00, 0x06, 'f', 'o', 'o', 'b', 'a', 'r'}, + 11, + ERROR_SUCCESS, + {SDP_TYPE_STRING, SDP_ST_NONE, .data = {.string = {&test_cases[2].stream[5], 6}}}, + "foobar", + } + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + winetest_push_context( TEST_CASE_NAME( i+1 ) ); + test_BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, test_cases[i].error, + &test_cases[i].data ); + if (test_cases[i].error == ERROR_SUCCESS) + { + SDP_ELEMENT_DATA result = {0}; + BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, &result ); + ok( strlen( test_cases[i].string ) == result.data.string.length, + "Expected string %s, got %s.\n", debugstr_a( test_cases[i].string ), + debugstr_an( (const char *)result.data.string.value, result.data.string.length ) ); + ok( !memcmp( result.data.string.value, test_cases[i].string, + result.data.string.length ), + "Expected string %s, got %s.\n", debugstr_a( test_cases[i].string ), + debugstr_an( (const char *)result.data.string.value, result.data.string.length ) ); + } + winetest_pop_context(); + } +} + +static void test_BluetoothSdpGetElementData_seq( void ) +{ + static struct { + BYTE stream[11]; + SIZE_T size; + DWORD error; + SDP_ELEMENT_DATA data; + SDP_ELEMENT_DATA sequence[6]; + SIZE_T container_size; + } test_cases[] = { + { + {SDP_TYPEDISC_SEQ8, 0x06, SDP_TYPEDISC_UINT8, 0xde, SDP_TYPEDISC_UINT8, 0xad, SDP_TYPEDISC_UINT8, 0xbe}, + 8, + ERROR_SUCCESS, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, .data = {.sequence = {&test_cases[0].stream[0], 8}}}, + { + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xad}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xbe}} + }, + 3 + }, + { + {SDP_TYPEDISC_SEQ16, 0x00, 0x06, SDP_TYPEDISC_UINT8, 0xde, SDP_TYPEDISC_UINT8, 0xad, SDP_TYPEDISC_UINT8, 0xbe}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, .data = {.sequence = {&test_cases[1].stream[0], 9}}}, + { + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xad}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xbe}} + }, + 3 + }, + { + {SDP_TYPEDISC_SEQ32, 0x00, 0x00, 0x00, 0x06, SDP_TYPEDISC_UINT8, 0xde, SDP_TYPEDISC_UINT8, 0xad, SDP_TYPEDISC_UINT8, 0xbe}, + 11, + ERROR_SUCCESS, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, .data = {.sequence = {&test_cases[2].stream[0], 11}}}, + { + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xad}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xbe}} + }, + 3 + }, + { + {SDP_TYPEDISC_SEQ8, SDP_TYPEDISC_UINT8, 0xde, SDP_TYPEDISC_UINT8, 0xad, SDP_TYPEDISC_UINT8, 0xbe}, + 1, + ERROR_INVALID_PARAMETER, + }, + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + SIZE_T n = 0; + HBLUETOOTH_CONTAINER_ELEMENT handle = NULL; + DWORD ret; + + winetest_push_context( TEST_CASE_NAME( i+1 ) ); + test_BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, test_cases[i].error, + &test_cases[i].data ); + if (test_cases[i].error != ERROR_SUCCESS) + { + winetest_pop_context(); + continue; + } + + while (n < test_cases[i].container_size) + { + SDP_ELEMENT_DATA container_elem = {0}; + + winetest_push_context( "test_cases[%d].sequence[%d]", (int)i, (int)n ); + ret = BluetoothSdpGetContainerElementData( test_cases[i].data.data.sequence.value, + test_cases[i].data.data.sequence.length, + &handle, &container_elem ); + if (ret == ERROR_NO_MORE_ITEMS) + { + ok( n == test_cases[i].container_size, "Expected %d elements, got %d.\n", + (int)test_cases[i].container_size, (int)n ); + winetest_pop_context(); + break; + } + ok( ret == ERROR_SUCCESS, "BluetoothSdpGetContainerElementData failed: %ld.\n", ret ); + if (ret == ERROR_SUCCESS) + { + ok( !memcmp( &test_cases[i].sequence[n], &container_elem, + sizeof( container_elem ) ), + "Expected %s, got %s.\n", debugstr_SDP_ELEMENT_DATA( &test_cases[i].sequence[n] ), + debugstr_SDP_ELEMENT_DATA( &container_elem ) ); + } + n++; + winetest_pop_context(); + } + winetest_pop_context(); + } +} + +START_TEST( sdp ) +{ + test_BluetoothSdpGetElementData_nil(); + test_BluetoothSdpGetElementData_ints(); + test_BluetoothSdpGetElementData_invalid(); + test_BluetoothSdpGetElementData_str(); + test_BluetoothSdpGetElementData_seq(); +}