[PATCH 2/2] dnsapi/tests: Add DnsQueryEx and DnsQuery_W tests (style)

Donat Enikeev donat at enikeev.net
Sun Jan 10 09:04:09 CST 2016


Minor changes adjusted per Nikolay Sivov feedback in IRC

Signed-off-by: Donat Enikeev <donat at enikeev.net>
---
 dlls/dnsapi/tests/Makefile.in |   3 +-
 dlls/dnsapi/tests/query.c     | 543 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 545 insertions(+), 1 deletion(-)
 create mode 100644 dlls/dnsapi/tests/query.c

diff --git a/dlls/dnsapi/tests/Makefile.in b/dlls/dnsapi/tests/Makefile.in
index 20412e8..d1f0930 100644
--- a/dlls/dnsapi/tests/Makefile.in
+++ b/dlls/dnsapi/tests/Makefile.in
@@ -3,4 +3,5 @@ IMPORTS   = dnsapi
 
 C_SRCS = \
 	name.c \
-	record.c
+	record.c \
+	query.c
diff --git a/dlls/dnsapi/tests/query.c b/dlls/dnsapi/tests/query.c
new file mode 100644
index 0000000..9c79cb0
--- /dev/null
+++ b/dlls/dnsapi/tests/query.c
@@ -0,0 +1,543 @@
+/* Unit test suite for DnsQuery* API functions
+ *
+ * Copyright (C) 2016 Donat Enikeev
+
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include "ntstatus.h"
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winnt.h"
+#include "winternl.h"
+#include "wine/test.h"
+
+#include "inaddr.h"
+#include "in6addr.h"
+#include "ws2tcpip.h"
+
+#include "winnls.h"
+#include "windns.h"
+#include "wine/test.h"
+
+#define DNS_QUERY_TEST_SHOW_TRACE 1
+#define dns_test_trace(args...) if (DNS_QUERY_TEST_SHOW_TRACE) winetest_trace(args);
+
+/* Function ptrs for helper data conversion calls when inet_ntop not available (ie mingw) */
+static HMODULE hntdll = 0;
+static CHAR *    (WINAPI *pRtlIpv6AddressToStringA)(const IN6_ADDR *, LPSTR);
+
+static HMODULE hdnsapi = 0;
+static DNS_STATUS(WINAPI *pDnsQueryEx) (DNS_QUERY_REQUEST *, DNS_QUERY_RESULT *, DNS_QUERY_CANCEL *);
+static DNS_STATUS(WINAPI *pDnsQuery_W) (PCWSTR , WORD , DWORD , PVOID , PDNS_RECORDW *, PVOID * );
+
+#ifndef AF_INET
+#define AF_INET 2
+#endif
+#ifndef AF_INET6
+#define AF_INET6 23
+#endif
+
+#define EXPECT_RECORD               1
+#define EXPECT_SEVERAL_RECORDS      2
+#define RESULT_TO_DO_WINE           4
+/* different windows platform reacts differently on non-existent domains or NS servers */
+#define RESULT_OK_ANY_NON_SUCCESS   8
+
+#define TODO_OR_OK(todo_condition,test_condition,subject...) if (todo_condition) { for (winetest_start_todo("wine"); \
+                            winetest_loop_todo(); \
+                            winetest_end_todo("wine")) { ok(test_condition, ##subject); }  } else { ok(test_condition, ##subject) ; }
+
+struct dnsqueryex_test_data {
+    LPCSTR query_name;
+    WORD query_type;
+    ULONG64 query_options;
+    DNS_STATUS expected_status;
+    ULONG flags;
+    LPCSTR dns_server_ip;
+};
+
+static struct dnsqueryex_test_data dnsqueryex_tests[] =
+{
+    /*  These entries - to test an usage of particular DNS server.
+        `Family` DNS returns stub for known adult domain (details https://dns.yandex.com/),
+        Please compare IPs with what usual DNS returns for some popular adult domain.
+        Commented for ethic reasons */
+/*  { "xxxx",        DNS_TYPE_A,     DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "77.88.8.7" },
+    { "xxxx",        DNS_TYPE_A,     DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.8.8" }, */
+
+
+    { "example.com",        DNS_TYPE_A,     DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.4.4" },
+    { "example.org",        DNS_TYPE_A,     DNS_QUERY_USE_TCP_ONLY,     ERROR_SUCCESS,              EXPECT_RECORD,  NULL },
+
+    /* Wine returns same error code for no records and wrong name DNS_ERROR_RCODE_NAME_ERROR */
+    { "google.com",         DNS_TYPE_SIG,   DNS_QUERY_STANDARD,         DNS_INFO_NO_RECORDS,        RESULT_TO_DO_WINE,  NULL },
+
+    /* PTR returned here, not SRV */
+    { "test.winehq.org",    DNS_TYPE_SRV,   DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  NULL },
+    { "test.winehq.org",    DNS_TYPE_SRV,   DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.8.8" },
+
+    /* Please replace with known-to widely work SRV record, this one unstable */
+    /* { "_nicname._tcp.us",    DNS_TYPE_SRV,   DNS_QUERY_STANDARD,        ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.4.4" }, */
+
+    { "winehq.org",         DNS_TYPE_SOA,   DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  NULL },
+    { "winehq.org",         DNS_TYPE_SOA,   DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.4.4" },
+
+    { "winehq.org",         DNS_TYPE_MX,    DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  NULL },
+    { "winehq.org",         DNS_TYPE_MX,    DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.8.8" },
+
+    { "winehq.org",         DNS_TYPE_NS,    DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD | EXPECT_SEVERAL_RECORDS,  NULL },
+    { "winehq.org",         DNS_TYPE_NS,    DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD | EXPECT_SEVERAL_RECORDS,  "8.8.8.8" },
+
+    { "test.winehq.org",    DNS_TYPE_A,     DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  NULL },
+
+    /* Wine returns ERROR_INVALID_NAME */
+    { "_._",                DNS_TYPE_A,     DNS_QUERY_STANDARD,         DNS_ERROR_RCODE_NAME_ERROR, RESULT_TO_DO_WINE,  "8.8.8.8" },
+
+    { "test.wine.org_or",   DNS_TYPE_AAAA,  DNS_QUERY_STANDARD,         DNS_ERROR_RCODE_NAME_ERROR, 0,  NULL },
+
+    /** windows 2008 returns DNS_ERROR_RCODE_NAME_ERROR */
+    { "unexistent",         DNS_TYPE_A,     DNS_QUERY_STANDARD,         ERROR_INVALID_NAME,         RESULT_OK_ANY_NON_SUCCESS,  NULL },
+
+    /* Punycoded domain */
+    { "xn--c1aay4a.xn--p1ai", DNS_TYPE_AAAA,DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.4.4" },
+
+    { "google.com",         DNS_TYPE_A,     DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD | EXPECT_SEVERAL_RECORDS, NULL },
+    { "google.com",         DNS_TYPE_A,     DNS_QUERY_USE_TCP_ONLY,     ERROR_SUCCESS,              EXPECT_RECORD | EXPECT_SEVERAL_RECORDS, "8.8.4.4"  },
+    { "google.com",         DNS_TYPE_AAAA,  DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.8.8" },
+    { "google.com",         DNS_TYPE_AAAA,  DNS_QUERY_USE_TCP_ONLY,     ERROR_SUCCESS,              EXPECT_RECORD,  "8.8.4.4" },
+
+    { "winehq.org",         DNS_TYPE_TEXT,  DNS_QUERY_STANDARD,         ERROR_SUCCESS,              EXPECT_RECORD,  NULL},
+
+    /* Wine returns same error code for no records and wrong name DNS_ERROR_RCODE_NAME_ERROR */
+    { "winehq.org",         DNS_TYPE_AAAA,  DNS_QUERY_STANDARD,         DNS_INFO_NO_RECORDS,        RESULT_TO_DO_WINE,  NULL},
+    { "winehq.org",         DNS_TYPE_CNAME, DNS_QUERY_STANDARD,         DNS_INFO_NO_RECORDS,        RESULT_TO_DO_WINE,  NULL },
+    { "winehq.org",         DNS_TYPE_CNAME, DNS_QUERY_STANDARD,         DNS_INFO_NO_RECORDS,        RESULT_TO_DO_WINE,  "8.8.4.4" },
+
+    { "localhost",          DNS_TYPE_A,     DNS_QUERY_NO_LOCAL_NAME
+                                            | DNS_QUERY_NO_HOSTS_FILE,  ERROR_INVALID_NAME,         0,  "8.8.4.4" },
+
+    /* Wine returns DNS_ERROR_RCODE_NAME_ERROR for AAAA */
+    { "localhost",          DNS_TYPE_AAAA,  DNS_QUERY_NO_LOCAL_NAME
+                                            | DNS_QUERY_NO_HOSTS_FILE,  ERROR_INVALID_NAME,         RESULT_TO_DO_WINE,  "8.8.8.8" },
+    /* Wine returns DNS_ERROR_RCODE_SERVER_FAILURE */
+    { "example.com",        DNS_TYPE_A,     DNS_QUERY_STANDARD,         ERROR_TIMEOUT,              RESULT_TO_DO_WINE,  "1.0.0.0" },
+};
+
+/** For easier cross-compile **/
+DWORD helper_ip2int(const char *ip)
+{
+    const char *end = ip + strlen(ip);
+    DWORD n = 0;
+    while (ip < end) {
+        n <<= 8;
+        n |= strtoul(ip, (char **)&ip, 10);
+        ip++;
+    }
+
+    return htonl(n);
+}
+
+const char *helper_dns_type_to_str( unsigned short type )
+{
+    switch (type)
+    {
+#define X(x)    case (x): return #x;
+    X(DNS_TYPE_ZERO)
+    X(DNS_TYPE_A)
+    X(DNS_TYPE_NS)
+    X(DNS_TYPE_MD)
+    X(DNS_TYPE_MF)
+    X(DNS_TYPE_CNAME)
+    X(DNS_TYPE_SOA)
+    X(DNS_TYPE_MB)
+    X(DNS_TYPE_MG)
+    X(DNS_TYPE_MR)
+    X(DNS_TYPE_NULL)
+    X(DNS_TYPE_WKS)
+    X(DNS_TYPE_PTR)
+    X(DNS_TYPE_HINFO)
+    X(DNS_TYPE_MINFO)
+    X(DNS_TYPE_MX)
+    X(DNS_TYPE_TEXT)
+    X(DNS_TYPE_RP)
+    X(DNS_TYPE_AFSDB)
+    X(DNS_TYPE_X25)
+    X(DNS_TYPE_ISDN)
+    X(DNS_TYPE_RT)
+    X(DNS_TYPE_NSAP)
+    X(DNS_TYPE_NSAPPTR)
+    X(DNS_TYPE_SIG)
+    X(DNS_TYPE_KEY)
+    X(DNS_TYPE_PX)
+    X(DNS_TYPE_GPOS)
+    X(DNS_TYPE_AAAA)
+    X(DNS_TYPE_LOC)
+    X(DNS_TYPE_NXT)
+    X(DNS_TYPE_EID)
+    X(DNS_TYPE_NIMLOC)
+    X(DNS_TYPE_SRV)
+    X(DNS_TYPE_ATMA)
+    X(DNS_TYPE_NAPTR)
+    X(DNS_TYPE_KX)
+    X(DNS_TYPE_CERT)
+    X(DNS_TYPE_A6)
+    X(DNS_TYPE_DNAME)
+    X(DNS_TYPE_SINK)
+    X(DNS_TYPE_OPT)
+    X(DNS_TYPE_UINFO)
+    X(DNS_TYPE_UID)
+    X(DNS_TYPE_GID)
+    X(DNS_TYPE_UNSPEC)
+    X(DNS_TYPE_ADDRS)
+    X(DNS_TYPE_TKEY)
+    X(DNS_TYPE_TSIG)
+    X(DNS_TYPE_IXFR)
+    X(DNS_TYPE_AXFR)
+    X(DNS_TYPE_MAILB)
+    X(DNS_TYPE_MAILA)
+    X(DNS_TYPE_ANY)
+    X(DNS_TYPE_WINS)
+    X(DNS_TYPE_WINSR)
+#undef X
+    default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; }
+    }
+}
+
+void helper_check_record(PDNS_RECORD record, struct dnsqueryex_test_data * test) {
+
+    dns_test_trace("Found record %p of type %s (%d) for %s; requested: %s (%d) \n", record,
+        helper_dns_type_to_str(record->wType), record->wType, test->query_name,
+        helper_dns_type_to_str(test->query_type), test->query_type);
+
+    switch (record->wType)
+    {
+        case DNS_TYPE_A:
+        {
+                CHAR data[IP4_ADDRESS_STRING_LENGTH];
+                DWORD i = record->Data.A.IpAddress;
+
+                ok ( i, "Zero ip returned %d for record %p\n", record->Data.A.IpAddress, record);
+
+                sprintf(data, "%i.%i.%i.%i", i & 0xFF, (i >> 8) & 0xFF, (i >> 16) & 0xFF, (i >> 24) & 0xFF);
+
+                dns_test_trace("IP address from A record: %s\n", (char *)&data);
+
+                ok ( strlen(data) >= 8,
+                        "Unexpected length of IPv4 '%s' in resulting record, at least 8 characters expected \n", (char *)&data);
+                return;
+        }
+        case DNS_TYPE_AAAA:
+        {
+                CHAR data[IP6_ADDRESS_STRING_LENGTH];
+                int converted = 0;
+#ifdef HAVE_INET_NTOP
+                inet_ntop(AF_INET6, &record->Data.AAAA.Ip6Address, &data, IP6_ADDRESS_STRING_LENGTH);
+                converted = 1;
+#else
+                if (pRtlIpv6AddressToStringA && !converted)
+                {
+                    pRtlIpv6AddressToStringA( (const IN6_ADDR *)&record->Data.AAAA.Ip6Address, (LPSTR) &data );
+                    converted = 1;
+                }
+#endif
+                if (converted)
+                {
+                    dns_test_trace("IPv6 address from AAAA record: %s\n", (char *)&data);
+                    ok ( strlen(data) >= 3 ,
+                            "Unexpected length of IPv6 '%s' in resulting record, at least 3 characters expected \n", (char *)&data);
+                } else
+                    skip("No conversion available for a IPv6 test, skipping\n");
+                return;
+        }
+        case DNS_TYPE_DNAME:
+        case DNS_TYPE_NS:
+        case DNS_TYPE_CNAME:
+        case DNS_TYPE_PTR:
+        {
+                ok (lstrlenW(record->Data.PTR.pNameHost),
+                    "NameHost expected, got %p\n", record->Data.PTR.pNameHost);
+
+                dns_test_trace("NameHost: %s\n", wine_dbgstr_w(record->Data.PTR.pNameHost));
+
+                return;
+        }
+        case DNS_TYPE_TEXT:
+        {       int i;
+                LPWSTR *string_array;
+
+                dns_test_trace("Strings count: %d\n", record->Data.TXT.dwStringCount);
+
+                string_array = (LPWSTR *)record->Data.TXT.pStringArray;
+
+                dns_test_trace("Strings count: %d\n", record->Data.TXT.dwStringCount);
+
+                ok (record->Data.TXT.dwStringCount,
+                    "At least one TXT record expected at %p \n", &record->Data);
+
+                for (i=0; i<record->Data.TXT.dwStringCount; i++)
+                {
+                    dns_test_trace("String[%d] = %s\n", i+1, wine_dbgstr_w(*string_array));
+                    string_array++;
+                }
+                return;
+        }
+        case DNS_TYPE_MX:
+        {
+                dns_test_trace("NameExchange: %s, preference %d\n", wine_dbgstr_w(record->Data.MX.pNameExchange), record->Data.MX.wPreference);
+
+                ok (lstrlenW(record->Data.MX.pNameExchange),
+                    "NameExchange expected at %p\n", record->Data.MX.pNameExchange);
+
+                return;
+        }
+        case DNS_TYPE_SOA:
+        {
+                dns_test_trace("n\tNamePrimaryServer = %s, NameAdministrator = %s, expire = %d\n",
+                    wine_dbgstr_w(record->Data.SOA.pNamePrimaryServer), wine_dbgstr_w(record->Data.SOA.pNameAdministrator), record->Data.SOA.dwExpire);
+
+                ok (lstrlenW(record->Data.SOA.pNamePrimaryServer),
+                    "NamePrimaryServer expected at %p\n", record->Data.SOA.pNamePrimaryServer);
+
+                ok (lstrlenW(record->Data.SOA.pNameAdministrator),
+                    "NameNameAdministrator expected at %p\n", record->Data.SOA.pNameAdministrator);
+
+                return;
+        }
+        case DNS_TYPE_SRV:
+        {
+                dns_test_trace("n\tNameTarget = %s, port = %d, priority = %d, weight = %d\n",
+                    wine_dbgstr_w(record->Data.SRV.pNameTarget), record->Data.SRV.wPort, record->Data.SRV.wPriority, record->Data.SRV.wWeight );
+
+                ok (lstrlenW(record->Data.SRV.pNameTarget),
+                    "NameTarget expected at %p\n", record->Data.SRV.pNameTarget);
+
+                return;
+        }
+        case DNS_TYPE_SIG:
+        {
+                dns_test_trace("NameSigner = %s, TimeSigned = %d, Expiration %d \n",
+                    wine_dbgstr_w(record->Data.SIG.pNameSigner), record->Data.SIG.dwTimeSigned, record->Data.SIG.dwExpiration);
+
+                ok (lstrlenW(record->Data.SIG.pNameSigner),
+                    "NameTarget expected at %p\n", record->Data.SIG.pNameSigner);
+
+                return;
+        }
+        default:
+        {
+                ok(0, " Seems tests are broken or irrelevant, unexpected type record %s (%d)\n", helper_dns_type_to_str(record->wType), record->wType);
+                return;
+        }
+    }
+}
+
+static void test_DnsQuery_W(void)
+{
+    const int test_count = sizeof(dnsqueryex_tests) / sizeof(dnsqueryex_tests[0]);
+    int i;
+
+    if (!pDnsQuery_W)
+    {
+        win_skip("DnsQuery_W not available on the platform; skipping\n");
+        return;
+    }
+
+    for (i=0; i<test_count; i++)
+    {
+        int res, records_cnt, query_name_len, test_flags;
+        PDNS_RECORD record = NULL;
+        LPWSTR query_name_W;
+        IP4_ARRAY t_ip;
+        PIP4_ARRAY p_dns_server;
+
+        p_dns_server = NULL;
+        memset(&t_ip, 0, sizeof(t_ip));
+
+        test_flags = dnsqueryex_tests[i].flags;
+
+        /* IP address to binary representation if particular DNS server defined*/
+        if ( dnsqueryex_tests[i].dns_server_ip )
+        {
+            t_ip.AddrArray[0] = helper_ip2int(dnsqueryex_tests[i].dns_server_ip);
+            t_ip.AddrCount = 1;
+
+            p_dns_server = &t_ip;
+        }
+
+        query_name_len = MultiByteToWideChar(CP_ACP, 0, dnsqueryex_tests[i].query_name, -1, NULL, 0);
+        query_name_W = HeapAlloc(GetProcessHeap(), 0, query_name_len*sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, dnsqueryex_tests[i].query_name, -1, query_name_W, query_name_len);
+
+        res = pDnsQuery_W (query_name_W, dnsqueryex_tests[i].query_type, dnsqueryex_tests[i].query_options, p_dns_server, &record, NULL);
+
+        dns_test_trace("DnsQuery_W result = %d (test #%d - %s %s)\n", res, i,
+            wine_dbgstr_w(query_name_W), helper_dns_type_to_str(dnsqueryex_tests[i].query_type));
+
+        TODO_OR_OK(test_flags & RESULT_TO_DO_WINE,
+            res==dnsqueryex_tests[i].expected_status || (res != ERROR_SUCCESS && test_flags & RESULT_OK_ANY_NON_SUCCESS),
+            "Unexpected status in result for test %d (%s %s), waited %u, got %u \n",
+                i, wine_dbgstr_w(query_name_W), helper_dns_type_to_str(dnsqueryex_tests[i].query_type), dnsqueryex_tests[i].expected_status, res);
+
+        ok ( dnsqueryex_tests[i].flags & EXPECT_RECORD || !record,
+            "Waited for at least one record in test %d,  no records received\n", i);
+
+        records_cnt = 0;
+
+        while(record) {
+            records_cnt++;
+            helper_check_record(record, &dnsqueryex_tests[i]);
+            record = record->pNext;
+        }
+
+        dns_test_trace("Total records in response: %d\n", records_cnt);
+
+        ok( !record || (dnsqueryex_tests[i].flags & EXPECT_SEVERAL_RECORDS) || (records_cnt>1),
+            "Flags (%d) Expected several records in result for %d test ('%s' for type %d), got %d \n", dnsqueryex_tests[i].flags & EXPECT_SEVERAL_RECORDS,
+                i, wine_dbgstr_w(query_name_W), dnsqueryex_tests[i].query_type, records_cnt);
+
+        HeapFree(GetProcessHeap(), 0, query_name_W);
+    }
+}
+
+static void test_DnsQueryEx(void)
+{
+    const int test_count = sizeof(dnsqueryex_tests) / sizeof(dnsqueryex_tests[0]);
+    int i;
+
+    if (!pDnsQueryEx)
+    {
+        win_skip("DnsQueryEx not available on the platform; skipping\n");
+        return;
+    }
+
+    for (i=0; i<test_count; i++)
+    {
+        int query_name_len;
+        DNS_STATUS status;
+        ULONG test_flags;
+        LPWSTR query_name_W;
+        DNS_QUERY_REQUEST request;
+        DNS_QUERY_RESULT result;
+        DNS_ADDR_ARRAY dns_addr_array;
+        SOCKADDR_IN t_sockaddr;
+
+        PDNS_RECORD record;
+        int records_cnt;
+
+        memset(&dns_addr_array, 0, sizeof(dns_addr_array));
+        memset(&request,0,sizeof(request));
+        memset(&result,0,sizeof(result));
+        memset(&t_sockaddr, 0, sizeof(t_sockaddr));
+
+        query_name_len = MultiByteToWideChar(CP_ACP, 0, dnsqueryex_tests[i].query_name, -1, NULL, 0);
+        query_name_W = HeapAlloc(GetProcessHeap(), 0, query_name_len*sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, dnsqueryex_tests[i].query_name, -1, query_name_W, query_name_len);
+
+        request.Version = DNS_QUERY_REQUEST_VERSION1;
+        request.QueryName = query_name_W;
+        request.QueryType = dnsqueryex_tests[i].query_type;
+        request.QueryOptions = dnsqueryex_tests[i].query_options;
+        request.pQueryCompletionCallback = NULL;
+
+        /** Not clearly defined in documentation of DnsQueryEx itself, but Version should be defined for a Result as well,
+            otherwise DnsQueryEx will always return ERROR_INVALID_PARAMETER (87) **/
+        result.Version = DNS_QUERY_RESULTS_VERSION1;
+
+        test_flags = dnsqueryex_tests[i].flags;
+
+        /* IP address to binary representation if particular DNS server defined*/
+        if ( dnsqueryex_tests[i].dns_server_ip ) {
+
+            t_sockaddr.sin_addr.s_addr = helper_ip2int(dnsqueryex_tests[i].dns_server_ip);
+            t_sockaddr.sin_family = AF_INET;
+
+            dns_addr_array.MaxCount = 1;
+            dns_addr_array.AddrCount = 1;
+            dns_addr_array.Family = AF_INET;
+
+            memcpy(&dns_addr_array.AddrArray[0].MaxSa, &t_sockaddr, sizeof(SOCKADDR_IN));
+
+            request.pDnsServerList = &dns_addr_array;
+        }
+
+        status = pDnsQueryEx(&request, &result, NULL);
+
+        dns_test_trace("DnsQueryEx status = %d (test #%d - %s:%s)\n", status, i,
+            wine_dbgstr_w(query_name_W), helper_dns_type_to_str(dnsqueryex_tests[i].query_type));
+
+        TODO_OR_OK(test_flags & RESULT_TO_DO_WINE,
+            status == dnsqueryex_tests[i].expected_status || (status != ERROR_SUCCESS && test_flags & RESULT_OK_ANY_NON_SUCCESS),
+            "Unexpected status in result for test %d ('%s' %s), waited %u, got %u \n",
+                i,  wine_dbgstr_w(query_name_W), helper_dns_type_to_str(dnsqueryex_tests[i].query_type), dnsqueryex_tests[i].expected_status, status );
+
+        record = result.pQueryRecords;
+
+        ok( test_flags & EXPECT_RECORD || !record,
+            "Waited for at least one record in test %d,  no records received\n", i);
+
+        records_cnt = 0;
+
+        while(record) {
+            records_cnt++;
+            helper_check_record(record, &dnsqueryex_tests[i]);
+            record = record->pNext;
+        }
+
+        dns_test_trace("Total records in response: %d\n", records_cnt);
+
+        ok( !record || (test_flags & EXPECT_SEVERAL_RECORDS) || (records_cnt>1),
+            "Flags (%d) Expected several records in result for %d test ('%s' for type %d), got %d \n", test_flags & EXPECT_SEVERAL_RECORDS,
+                i,  wine_dbgstr_w(query_name_W), dnsqueryex_tests[i].query_type, records_cnt);
+
+        HeapFree(GetProcessHeap(), 0, query_name_W);
+    }
+}
+
+static void InitFunctionPtrs(void)
+{
+
+    hntdll = LoadLibraryA("ntdll.dll");
+    ok(hntdll != 0, "LoadLibrary failed\n");
+    if (hntdll) {
+        pRtlIpv6AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringA");
+    }
+
+    hdnsapi = LoadLibraryA("dnsapi.dll");
+    ok(hdnsapi != 0, "LoadLibrary failed\n");
+    if (hdnsapi) {
+        pDnsQueryEx = (void *)GetProcAddress(hdnsapi, "DnsQueryEx");
+        pDnsQuery_W = (void *)GetProcAddress(hdnsapi, "DnsQuery_W");
+    }
+}
+
+
+START_TEST(query)
+{
+    InitFunctionPtrs();
+
+    test_DnsQuery_W();
+
+    test_DnsQueryEx();
+}
\ No newline at end of file
-- 
2.5.0




More information about the wine-patches mailing list