Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
An alternative implementation of 212857-212859, in a much cleaner way IMHO. This however introduces a new "winetest" static library, although it is optional for tests which do not require driver testing.
The library is used to share the driver signing, loading, and interop code, using a separate "wine/test_driver.h" header file.
If "wine/test.h" was previously included, the header is defining the user-space interface, if not it declares the driver-space test functions instead.
I can imagine that the library could also be used to share other testing code, although keeping it optional is probably better.
The individual drivers would still need to be implemented in each module (and driver_hid potentially duplicated) but it's not too bad.
dlls/ntoskrnl.exe/tests/utils.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h index f73f6f938ca..de632c65b7c 100644 --- a/dlls/ntoskrnl.exe/tests/utils.h +++ b/dlls/ntoskrnl.exe/tests/utils.h @@ -178,19 +178,31 @@ static inline NTSTATUS winetest_init(void) FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); }
-static inline void winetest_cleanup(void) +#define winetest_cleanup() winetest_cleanup_(__FILE__) +static inline void winetest_cleanup_(const char *file) { + char test_name[MAX_PATH], *tmp; struct test_data *data; SIZE_T size = sizeof(*data); + const char *source_file; OBJECT_ATTRIBUTES attr; UNICODE_STRING string; void *addr = NULL; HANDLE section;
+ source_file = strrchr(file, '/'); + if (!source_file) source_file = strrchr(file, '\'); + if (!source_file) source_file = file; + else source_file++; + + strcpy(test_name, source_file); + if ((tmp = strrchr(test_name, '.'))) *tmp = 0; + if (winetest_debug) { - kprintf("%04x:ntoskrnl: %d tests executed (%d marked as todo, %d %s), %d skipped.\n", - (DWORD)(DWORD_PTR)PsGetCurrentProcessId(), successes + failures + todo_successes + todo_failures, + kprintf("%04x:%s: %d tests executed (%d marked as todo, %d %s), %d skipped.\n", + (DWORD)(DWORD_PTR)PsGetCurrentProcessId(), test_name, + successes + failures + todo_successes + todo_failures, todo_successes, failures + todo_failures, (failures + todo_failures != 1) ? "failures" : "failure", skipped ); }
To share driver signing, loading and testing code. Its use is optional, and the interface is available in a new "wine/test_driver.h" header.
Tests which do not need a driver stay standalone, using "wine/test.h" only.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure.ac | 1 + dlls/winetest/Makefile.in | 4 + dlls/winetest/winetest_driver.c | 569 ++++++++++++++++++++++++++++++++ include/wine/test_driver.h | 492 +++++++++++++++++++++++++++ 4 files changed, 1066 insertions(+) create mode 100644 dlls/winetest/Makefile.in create mode 100644 dlls/winetest/winetest_driver.c create mode 100644 include/wine/test_driver.h
diff --git a/configure.ac b/configure.ac index 594794ed93c..56422a4fb6a 100644 --- a/configure.ac +++ b/configure.ac @@ -3795,6 +3795,7 @@ WINE_CONFIG_MAKEFILE(dlls/wineps.drv) WINE_CONFIG_MAKEFILE(dlls/wineps16.drv16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/winepulse.drv) WINE_CONFIG_MAKEFILE(dlls/wineqtdecoder) +WINE_CONFIG_MAKEFILE(dlls/winetest) WINE_CONFIG_MAKEFILE(dlls/wineusb.sys) WINE_CONFIG_MAKEFILE(dlls/winevulkan) WINE_CONFIG_MAKEFILE(dlls/winex11.drv) diff --git a/dlls/winetest/Makefile.in b/dlls/winetest/Makefile.in new file mode 100644 index 00000000000..d4d092d993f --- /dev/null +++ b/dlls/winetest/Makefile.in @@ -0,0 +1,4 @@ +MODULE = libwinetest.a + +C_SRCS = \ + winetest_driver.c diff --git a/dlls/winetest/winetest_driver.c b/dlls/winetest/winetest_driver.c new file mode 100644 index 00000000000..9d5202f09df --- /dev/null +++ b/dlls/winetest/winetest_driver.c @@ -0,0 +1,569 @@ +/* + * Wine testing framework - Driver test helpers + * + * Copyright 2015 Sebastian Lackner + * Copyright 2015 Michael Müller + * Copyright 2015 Christian Costa + * + * 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 <stddef.h> +#include <time.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winioctl.h" +#include "winternl.h" +#include "winuser.h" +#include "winnls.h" +#include "winsvc.h" +#include "winreg.h" +#include "wincrypt.h" + +#include "mscat.h" +#include "newdev.h" +#include "ntsecapi.h" +#include "objbase.h" +#include "setupapi.h" + +#include "wine/mssign.h" +#include "wine/test.h" +#include "wine/test_driver.h" + +static HANDLE test_data_mapping; +static struct winetest_shared_data *test_data; + +static HRESULT (WINAPI *pSignerSign)(SIGNER_SUBJECT_INFO *subject, SIGNER_CERT *cert, + SIGNER_SIGNATURE_INFO *signature, SIGNER_PROVIDER_INFO *provider, + const WCHAR *timestamp, CRYPT_ATTRIBUTES *attr, void *sip_data); + +static void load_resource(const WCHAR *name, WCHAR *filename) +{ + static WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(ARRAY_SIZE(path), path); + GetTempFileNameW(path, name, 0, filename); + + file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %u\n", debugstr_w(filename), GetLastError()); + + res = FindResourceW(NULL, name, L"TESTDLL"); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleW(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleW(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleW(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + +static BOOL testsign_create_cert(struct winetest_driver_context *ctx) +{ + BYTE encoded_name[100], encoded_key_id[200], public_key_info_buffer[1000]; + WCHAR container_name[26]; + BYTE hash_buffer[16], cert_buffer[1000], provider_nameA[100], serial[16]; + CERT_PUBLIC_KEY_INFO *public_key_info = (CERT_PUBLIC_KEY_INFO *)public_key_info_buffer; + CRYPT_KEY_PROV_INFO provider_info = {0}; + CRYPT_ALGORITHM_IDENTIFIER algid = {0}; + CERT_AUTHORITY_KEY_ID_INFO key_info; + CERT_INFO cert_info = {0}; + WCHAR provider_nameW[100]; + CERT_EXTENSION extension; + HCRYPTKEY key; + DWORD size; + BOOL ret; + + memset(ctx, 0, sizeof(*ctx)); + + srand(time(NULL)); + swprintf(container_name, ARRAY_SIZE(container_name), L"wine_testsign%u", rand()); + + ret = CryptAcquireContextW(&ctx->provider, container_name, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET); + ok(ret, "Failed to create container, error %u\n", GetLastError()); + + ret = CryptGenKey(ctx->provider, AT_SIGNATURE, CRYPT_EXPORTABLE, &key); + ok(ret, "Failed to create key, error %u\n", GetLastError()); + ret = CryptDestroyKey(key); + ok(ret, "Failed to destroy key, error %u\n", GetLastError()); + ret = CryptGetUserKey(ctx->provider, AT_SIGNATURE, &key); + ok(ret, "Failed to get user key, error %u\n", GetLastError()); + ret = CryptDestroyKey(key); + ok(ret, "Failed to destroy key, error %u\n", GetLastError()); + + size = sizeof(encoded_name); + ret = CertStrToNameW(X509_ASN_ENCODING, L"CN=winetest_cert", CERT_X500_NAME_STR, NULL, encoded_name, &size, NULL); + ok(ret, "Failed to convert name, error %u\n", GetLastError()); + key_info.CertIssuer.cbData = size; + key_info.CertIssuer.pbData = encoded_name; + + size = sizeof(public_key_info_buffer); + ret = CryptExportPublicKeyInfo(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, public_key_info, &size); + ok(ret, "Failed to export public key, error %u\n", GetLastError()); + cert_info.SubjectPublicKeyInfo = *public_key_info; + + size = sizeof(hash_buffer); + ret = CryptHashPublicKeyInfo(ctx->provider, CALG_MD5, 0, X509_ASN_ENCODING, public_key_info, hash_buffer, &size); + ok(ret, "Failed to hash public key, error %u\n", GetLastError()); + + key_info.KeyId.cbData = size; + key_info.KeyId.pbData = hash_buffer; + + RtlGenRandom(serial, sizeof(serial)); + key_info.CertSerialNumber.cbData = sizeof(serial); + key_info.CertSerialNumber.pbData = serial; + + size = sizeof(encoded_key_id); + ret = CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &key_info, encoded_key_id, &size); + ok(ret, "Failed to convert name, error %u\n", GetLastError()); + + extension.pszObjId = (char *)szOID_AUTHORITY_KEY_IDENTIFIER; + extension.fCritical = TRUE; + extension.Value.cbData = size; + extension.Value.pbData = encoded_key_id; + + cert_info.dwVersion = CERT_V3; + cert_info.SerialNumber = key_info.CertSerialNumber; + cert_info.SignatureAlgorithm.pszObjId = (char *)szOID_RSA_SHA1RSA; + cert_info.Issuer = key_info.CertIssuer; + GetSystemTimeAsFileTime(&cert_info.NotBefore); + GetSystemTimeAsFileTime(&cert_info.NotAfter); + cert_info.NotAfter.dwHighDateTime += 1; + cert_info.Subject = key_info.CertIssuer; + cert_info.cExtension = 1; + cert_info.rgExtension = &extension; + algid.pszObjId = (char *)szOID_RSA_SHA1RSA; + size = sizeof(cert_buffer); + ret = CryptSignAndEncodeCertificate(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, &cert_info, &algid, NULL, cert_buffer, &size); + ok(ret, "Failed to create certificate, error %u\n", GetLastError()); + + ctx->cert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_buffer, size); + ok(!!ctx->cert, "Failed to create context, error %u\n", GetLastError()); + + size = sizeof(provider_nameA); + ret = CryptGetProvParam(ctx->provider, PP_NAME, provider_nameA, &size, 0); + ok(ret, "Failed to get prov param, error %u\n", GetLastError()); + MultiByteToWideChar(CP_ACP, 0, (char *)provider_nameA, -1, provider_nameW, ARRAY_SIZE(provider_nameW)); + + provider_info.pwszContainerName = (WCHAR *)container_name; + provider_info.pwszProvName = provider_nameW; + provider_info.dwProvType = PROV_RSA_FULL; + provider_info.dwKeySpec = AT_SIGNATURE; + ret = CertSetCertificateContextProperty(ctx->cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provider_info); + ok(ret, "Failed to set provider info, error %u\n", GetLastError()); + + ctx->root_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "root"); + if (!ctx->root_store && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Failed to open root store.\n"); + + ret = CertFreeCertificateContext(ctx->cert); + ok(ret, "Failed to free certificate, error %u\n", GetLastError()); + ret = CryptReleaseContext(ctx->provider, 0); + ok(ret, "failed to release context, error %u\n", GetLastError()); + + return FALSE; + } + ok(!!ctx->root_store, "Failed to open store, error %u\n", GetLastError()); + ret = CertAddCertificateContextToStore(ctx->root_store, ctx->cert, CERT_STORE_ADD_ALWAYS, &ctx->root_cert); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Failed to add self-signed certificate to store.\n"); + + ret = CertFreeCertificateContext(ctx->cert); + ok(ret, "Failed to free certificate, error %u\n", GetLastError()); + ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); + ok(ret, "Failed to close store, error %u\n", GetLastError()); + ret = CryptReleaseContext(ctx->provider, 0); + ok(ret, "failed to release context, error %u\n", GetLastError()); + + return FALSE; + } + ok(ret, "Failed to add certificate, error %u\n", GetLastError()); + + ctx->publisher_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE, "trustedpublisher"); + ok(!!ctx->publisher_store, "Failed to open store, error %u\n", GetLastError()); + ret = CertAddCertificateContextToStore(ctx->publisher_store, ctx->cert, + CERT_STORE_ADD_ALWAYS, &ctx->publisher_cert); + ok(ret, "Failed to add certificate, error %u\n", GetLastError()); + + return TRUE; +} + +static void testsign_cleanup(struct winetest_driver_context *ctx) +{ + BOOL ret; + + ret = CertFreeCertificateContext(ctx->cert); + ok(ret, "Failed to free certificate, error %u\n", GetLastError()); + + ret = CertDeleteCertificateFromStore(ctx->root_cert); + ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); + ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); + ok(ret, "Failed to close store, error %u\n", GetLastError()); + + ret = CertDeleteCertificateFromStore(ctx->publisher_cert); + ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); + ret = CertCloseStore(ctx->publisher_store, CERT_CLOSE_STORE_CHECK_FLAG); + ok(ret, "Failed to close store, error %u\n", GetLastError()); + + ret = CryptReleaseContext(ctx->provider, 0); + ok(ret, "failed to release context, error %u\n", GetLastError()); +} + +static void testsign_sign(struct winetest_driver_context *ctx, const WCHAR *filename) +{ + SIGNER_ATTR_AUTHCODE authcode = {sizeof(authcode)}; + SIGNER_SIGNATURE_INFO signature = {sizeof(signature)}; + SIGNER_SUBJECT_INFO subject = {sizeof(subject)}; + SIGNER_CERT_STORE_INFO store = {sizeof(store)}; + SIGNER_CERT cert_info = {sizeof(cert_info)}; + SIGNER_FILE_INFO file = {sizeof(file)}; + DWORD index = 0; + HRESULT hr; + + subject.dwSubjectChoice = 1; + subject.pdwIndex = &index; + subject.pSignerFileInfo = &file; + file.pwszFileName = (WCHAR *)filename; + cert_info.dwCertChoice = 2; + cert_info.pCertStoreInfo = &store; + store.pSigningCert = ctx->cert; + store.dwCertPolicy = 0; + signature.algidHash = CALG_SHA_256; + signature.dwAttrChoice = SIGNER_AUTHCODE_ATTR; + signature.pAttrAuthcode = &authcode; + authcode.pwszName = L""; + authcode.pwszInfo = L""; + hr = pSignerSign(&subject, &cert_info, &signature, NULL, NULL, NULL, NULL); + todo_wine ok(hr == S_OK || broken(hr == NTE_BAD_ALGID) /* < 7 */, "Failed to sign, hr %#x\n", hr); +} + +static void unload_driver(SC_HANDLE service) +{ + SERVICE_STATUS status; + + ControlService(service, SERVICE_CONTROL_STOP, &status); + while (status.dwCurrentState == SERVICE_STOP_PENDING) + { + BOOL ret; + Sleep(100); + ret = QueryServiceStatus(service, &status); + ok(ret, "QueryServiceStatus failed: %u\n", GetLastError()); + } + ok(status.dwCurrentState == SERVICE_STOPPED, + "expected SERVICE_STOPPED, got %d\n", status.dwCurrentState); + + DeleteService(service); + CloseServiceHandle(service); +} + +static HANDLE okfile; + +void winetest_driver_check_failures(void) +{ + char buffer[512]; + DWORD size; + + SetFilePointer(okfile, 0, NULL, FILE_BEGIN); + + do + { + ReadFile(okfile, buffer, sizeof(buffer), &size, NULL); + printf("%.*s", size, buffer); + } while (size == sizeof(buffer)); + + SetFilePointer(okfile, 0, NULL, FILE_BEGIN); + SetEndOfFile(okfile); + + winetest_add_failures(InterlockedExchange(&test_data->failures, 0)); + winetest_add_failures(InterlockedExchange(&test_data->todo_failures, 0)); +} + +#ifdef __i386__ +#define EXT "x86" +#elif defined(__x86_64__) +#define EXT "amd64" +#elif defined(__arm__) +#define EXT "arm" +#elif defined(__aarch64__) +#define EXT "arm64" +#else +#define EXT +#endif + +static const char inf_text[] = + "[Version]\n" + "Signature=$Chicago$\n" + "ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}\n" + "CatalogFile=winetest.cat\n" + "DriverVer=09/21/2006,6.0.5736.1\n" + + "[Manufacturer]\n" + "Wine=mfg_section,NT" EXT "\n" + + "[mfg_section.NT" EXT "]\n" + "Wine test root driver=device_section,test_hardware_id\n" + + "[device_section.NT" EXT "]\n" + "CopyFiles=file_section\n" + + "[device_section.NT" EXT ".Services]\n" + "AddService=winetest,0x2,svc_section\n" + + "[file_section]\n" + "winetest.sys\n" + + "[SourceDisksFiles]\n" + "winetest.sys=1\n" + + "[SourceDisksNames]\n" + "1=,winetest.sys\n" + + "[DestinationDirs]\n" + "DefaultDestDir=12\n" + + "[svc_section]\n" + "ServiceBinary=%12%\winetest.sys\n" + "ServiceType=1\n" + "StartType=3\n" + "ErrorControl=1\n" + "LoadOrderGroup=Extended Base\n" + "DisplayName="winetest bus driver"\n" + "; they don't sleep anymore, on the beach\n"; + +static void add_file_to_catalog(HANDLE catalog, const WCHAR *file) +{ + SIP_SUBJECTINFO subject_info = {sizeof(SIP_SUBJECTINFO)}; + SIP_INDIRECT_DATA *indirect_data; + const WCHAR *filepart = file; + CRYPTCATMEMBER *member; + WCHAR hash_buffer[100]; + GUID subject_guid; + unsigned int i; + DWORD size; + BOOL ret; + + ret = CryptSIPRetrieveSubjectGuidForCatalogFile(file, NULL, &subject_guid); + todo_wine ok(ret, "Failed to get subject guid, error %u\n", GetLastError()); + + size = 0; + subject_info.pgSubjectType = &subject_guid; + subject_info.pwsFileName = file; + subject_info.DigestAlgorithm.pszObjId = (char *)szOID_OIWSEC_sha1; + subject_info.dwFlags = SPC_INC_PE_RESOURCES_FLAG | SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG | SPC_EXC_PE_PAGE_HASHES_FLAG | 0x10000; + ret = CryptSIPCreateIndirectData(&subject_info, &size, NULL); + todo_wine ok(ret, "Failed to get indirect data size, error %u\n", GetLastError()); + + indirect_data = malloc(size); + ret = CryptSIPCreateIndirectData(&subject_info, &size, indirect_data); + todo_wine ok(ret, "Failed to get indirect data, error %u\n", GetLastError()); + if (ret) + { + memset(hash_buffer, 0, sizeof(hash_buffer)); + for (i = 0; i < indirect_data->Digest.cbData; ++i) + swprintf(&hash_buffer[i * 2], 2, L"%02X", indirect_data->Digest.pbData[i]); + + member = CryptCATPutMemberInfo(catalog, (WCHAR *)file, + hash_buffer, &subject_guid, 0, size, (BYTE *)indirect_data); + ok(!!member, "Failed to write member, error %u\n", GetLastError()); + + if (wcsrchr(file, '\')) + filepart = wcsrchr(file, '\') + 1; + + ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"File", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + (wcslen(filepart) + 1) * 2, (BYTE *)filepart); + ok(ret, "Failed to write attr, error %u\n", GetLastError()); + + ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"OSAttr", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + sizeof(L"2:6.0"), (BYTE *)L"2:6.0"); + ok(ret, "Failed to write attr, error %u\n", GetLastError()); + } +} + +BOOL winetest_driver_start(struct winetest_driver_context *ctx, const WCHAR *resource) +{ + static const WCHAR hardware_id[] = L"test_hardware_id\0"; + WCHAR path[MAX_PATH], tempdir[MAX_PATH], filename[MAX_PATH]; + SC_HANDLE manager, service; + BOOL ret, need_reboot; + HANDLE catalog; + FILE *f; + + GetCurrentDirectoryW(ARRAY_SIZE(ctx->cwd), ctx->cwd); + GetTempPathW(ARRAY_SIZE(tempdir), tempdir); + SetCurrentDirectoryW(tempdir); + + load_resource(resource, filename); + ret = MoveFileExW(filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); + ok(ret, "failed to move file, error %u\n", GetLastError()); + + f = fopen("winetest.inf", "w"); + ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); + fputs(inf_text, f); + fclose(f); + + /* Create the catalog file. */ + + catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); + ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %u\n", GetLastError()); + + add_file_to_catalog(catalog, L"winetest.sys"); + add_file_to_catalog(catalog, L"winetest.inf"); + + ret = CryptCATPersistStore(catalog); + todo_wine ok(ret, "Failed to write catalog, error %u\n", GetLastError()); + + ret = CryptCATClose(catalog); + ok(ret, "Failed to close catalog, error %u\n", GetLastError()); + + testsign_sign(ctx, L"winetest.cat"); + + /* Install the driver. */ + + ctx->set = SetupDiCreateDeviceInfoList(NULL, NULL); + ok(ctx->set != INVALID_HANDLE_VALUE, "failed to create device list, error %u\n", GetLastError()); + + ctx->device.cbSize = sizeof(ctx->device); + ret = SetupDiCreateDeviceInfoW(ctx->set, L"root\winetest\0", &GUID_NULL, NULL, NULL, 0, &ctx->device); + ok(ret, "failed to create device, error %u\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyW( ctx->set, &ctx->device, SPDRP_HARDWAREID, + (const BYTE *)hardware_id, sizeof(hardware_id) ); + ok(ret, "failed to create set hardware ID, error %u\n", GetLastError()); + + ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, ctx->set, &ctx->device); + ok(ret, "failed to register device, error %u\n", GetLastError()); + + GetFullPathNameW(L"winetest.inf", sizeof(path), path, NULL); + ret = UpdateDriverForPlugAndPlayDevicesW(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); + ok(ret, "failed to install device, error %u\n", GetLastError()); + ok(!need_reboot, "expected no reboot necessary\n"); + + /* Check that the service is created and started. */ + manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); + ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); + service = OpenServiceW(manager, L"winetest", SERVICE_START | SERVICE_STOP | DELETE); + ok(!!service, "failed to open service, error %u\n", GetLastError()); + + ret = StartServiceW(service, 0, NULL); + ok(!ret, "service didn't start automatically\n"); + if (!ret && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) + { + /* If Secure Boot is enabled or the machine is 64-bit, it will reject an unsigned driver. */ + ok(GetLastError() == ERROR_DRIVER_BLOCKED || GetLastError() == ERROR_INVALID_IMAGE_HASH, + "unexpected error %u\n", GetLastError()); + skip("Failed to start service; probably your machine doesn't accept unsigned drivers.\n"); + } + + CloseServiceHandle(service); + CloseServiceHandle(manager); + return ret || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING; +} + +void winetest_driver_stop(struct winetest_driver_context *ctx) +{ + WCHAR path[MAX_PATH], dest[MAX_PATH], *filepart; + SC_HANDLE manager, service; + HANDLE file; + BOOL ret; + + ret = SetupDiCallClassInstaller(DIF_REMOVE, ctx->set, &ctx->device); + ok(ret, "failed to remove device, error %u\n", GetLastError()); + + file = CreateFileW(L"\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); + + ret = SetupDiDestroyDeviceInfoList(ctx->set); + ok(ret, "failed to destroy set, error %u\n", GetLastError()); + + /* Windows stops the service but does not delete it. */ + manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); + ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); + service = OpenServiceW(manager, L"winetest", SERVICE_STOP | DELETE); + ok(!!service, "failed to open service, error %u\n", GetLastError()); + + unload_driver(service); + CloseServiceHandle(manager); + + winetest_driver_check_failures(); + + GetFullPathNameW(L"winetest.inf", sizeof(path), path, NULL); + ret = SetupCopyOEMInfW(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); + ok(ret, "Failed to copy INF, error %u\n", GetLastError()); + ret = SetupUninstallOEMInfW(filepart, 0, NULL); + ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); + + ret = DeleteFileW(L"winetest.cat"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileW(L"winetest.inf"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileW(L"winetest.sys"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ + ret = DeleteFileW(L"C:/windows/system32/drivers/winetest.sys"); + ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); + + SetCurrentDirectoryW(ctx->cwd); +} + +BOOL winetest_driver_init_(struct winetest_driver_context *ctx) +{ + BOOL is_wow64; + + pSignerSign = (void *)GetProcAddress(LoadLibraryW(L"mssign32"), "SignerSign"); + + if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64) + { + skip("Running in WoW64.\n"); + return FALSE; + } + + if (!testsign_create_cert(ctx)) + return FALSE; + + test_data_mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, sizeof(*test_data), L"Global\winetest_driver_section"); + ok(!!test_data_mapping, "got error %u\n", GetLastError()); + test_data = MapViewOfFile(test_data_mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024); + test_data->running_under_wine = !strcmp(winetest_platform, "wine"); + test_data->winetest_report_success = winetest_report_success; + test_data->winetest_debug = winetest_debug; + + okfile = CreateFileW(L"C:\windows\winetest_driver_okfile", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); + ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError()); + + return TRUE; +} + +void winetest_driver_cleanup(struct winetest_driver_context *ctx) +{ + testsign_cleanup(ctx); + UnmapViewOfFile(test_data); + CloseHandle(test_data_mapping); + CloseHandle(okfile); + DeleteFileW(L"C:\windows\winetest_driver_okfile"); +} diff --git a/include/wine/test_driver.h b/include/wine/test_driver.h new file mode 100644 index 00000000000..b832c572533 --- /dev/null +++ b/include/wine/test_driver.h @@ -0,0 +1,492 @@ +/* + * Wine testing framework - Driver test helpers + * + * Copyright 2015 Sebastian Lackner + * Copyright 2015 Michael Müller + * Copyright 2015 Christian Costa + * Copyright 2020 Paul Gofman for CodeWeavers + * Copyright 2020-2021 Zebediah Figura for CodeWeavers + * + * 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 + */ + +#ifndef __WINE_WINE_TEST_DRIVER_H +#define __WINE_WINE_TEST_DRIVER_H + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include <windef.h> +#include <winbase.h> +#include <winternl.h> + +#include <ddk/wdm.h> + +/* kernel/user shared data */ +struct winetest_shared_data +{ + int running_under_wine; + int winetest_report_success; + int winetest_debug; + int failures; + int todo_failures; +}; + +#ifdef __WINE_WINE_TEST_H + +/* user-space test API */ +struct winetest_driver_context +{ + HCRYPTPROV provider; + const CERT_CONTEXT *cert; + const CERT_CONTEXT *root_cert; + const CERT_CONTEXT *publisher_cert; + HCERTSTORE root_store; + HCERTSTORE publisher_store; + + WCHAR cwd[MAX_PATH]; + HDEVINFO set; + SP_DEVINFO_DATA device; +}; + +#define winetest_driver_init(a) (subtest("winetest_driver"), winetest_driver_init_(a)) +extern BOOL winetest_driver_init_( struct winetest_driver_context *ctx ); +extern void winetest_driver_cleanup( struct winetest_driver_context *ctx ); +extern BOOL winetest_driver_start( struct winetest_driver_context *ctx, const WCHAR *resource ); +extern void winetest_driver_stop( struct winetest_driver_context *ctx ); +extern void winetest_driver_check_failures( void ); + +#else + +#if !defined(__WINE_USE_MSVCRT) || defined(__MINGW32__) +#define __WINE_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args))) +#else +#define __WINE_PRINTF_ATTR(fmt,args) +#endif + +static HANDLE okfile; +static LONG successes; +static LONG failures; +static LONG skipped; +static LONG todo_successes; +static LONG todo_failures; +static LONG muted_traces; +static LONG muted_skipped; +static LONG muted_todo_successes; + +static int running_under_wine; +static int winetest_debug; +static int winetest_report_success; + +/* silence todos and skips above this threshold */ +static int winetest_mute_threshold = 42; + +/* counts how many times a given line printed a message */ +static LONG line_counters[16384]; + +/* The following data must be kept track of on a per-thread basis */ +struct tls_data +{ + HANDLE thread; + const char* current_file; /* file of current check */ + int current_line; /* line of current check */ + unsigned int todo_level; /* current todo nesting level */ + int todo_do_loop; + char *str_pos; /* position in debug buffer */ + char strings[2000]; /* buffer for debug strings */ + char context[8][128]; /* data to print before messages */ + unsigned int context_count; /* number of context prefixes */ +}; + +static KSPIN_LOCK tls_data_lock; +static struct tls_data tls_data_pool[128]; +static DWORD tls_data_count; + +static inline struct tls_data *get_tls_data(void) +{ + static struct tls_data tls_overflow; + struct tls_data *data; + HANDLE thread = PsGetCurrentThreadId(); + KIRQL irql; + + KeAcquireSpinLock(&tls_data_lock, &irql); + for (data = tls_data_pool; data != tls_data_pool + tls_data_count; ++data) + if (data->thread == thread) break; + if (data == tls_data_pool + ARRAY_SIZE(tls_data_pool)) + data = &tls_overflow; + else if (data == tls_data_pool + tls_data_count) + { + data->thread = thread; + data->str_pos = data->strings; + tls_data_count++; + } + KeReleaseSpinLock(&tls_data_lock, irql); + + return data; +} + +static inline void winetest_set_location( const char* file, int line ) +{ + struct tls_data *data = get_tls_data(); + data->current_file=strrchr(file,'/'); + if (data->current_file==NULL) + data->current_file=strrchr(file,'\'); + if (data->current_file==NULL) + data->current_file=file; + else + data->current_file++; + data->current_line=line; +} + +static inline void kvprintf(const char *format, __ms_va_list ap) +{ + struct tls_data *data = get_tls_data(); + IO_STATUS_BLOCK io; + int len = vsnprintf(data->strings, sizeof(data->strings), format, ap); + ZwWriteFile(okfile, NULL, NULL, NULL, &io, data->strings, len, NULL, NULL); +} + +static inline void WINAPIV kprintf(const char *format, ...) __WINE_PRINTF_ATTR(1,2); +static inline void WINAPIV kprintf(const char *format, ...) +{ + __ms_va_list valist; + + __ms_va_start(valist, format); + kvprintf(format, valist); + __ms_va_end(valist); +} + +static inline void WINAPIV winetest_printf( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); +static inline void WINAPIV winetest_printf( const char *msg, ... ) +{ + struct tls_data *data = get_tls_data(); + __ms_va_list valist; + + kprintf( "%s:%d: ", data->current_file, data->current_line ); + __ms_va_start( valist, msg ); + kvprintf( msg, valist ); + __ms_va_end( valist ); +} + +static inline NTSTATUS winetest_init(void) +{ + const struct winetest_shared_data *data; + SIZE_T size = sizeof(*data); + OBJECT_ATTRIBUTES attr; + UNICODE_STRING string; + IO_STATUS_BLOCK io; + void *addr = NULL; + HANDLE section; + NTSTATUS ret; + + KeInitializeSpinLock(&tls_data_lock); + + RtlInitUnicodeString(&string, L"\BaseNamedObjects\winetest_driver_section"); + /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */ + InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL); + if ((ret = ZwOpenSection(§ion, SECTION_MAP_READ, &attr))) + return ret; + + if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr, + 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY))) + { + ZwClose(section); + return ret; + } + data = addr; + running_under_wine = data->running_under_wine; + winetest_debug = data->winetest_debug; + winetest_report_success = data->winetest_report_success; + + ZwUnmapViewOfSection(NtCurrentProcess(), addr); + ZwClose(section); + + RtlInitUnicodeString(&string, L"\??\C:\windows\winetest_driver_okfile"); + return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io, + FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); +} + +#define winetest_cleanup() winetest_cleanup_(__FILE__) +static inline void winetest_cleanup_(const char *file) +{ + char test_name[MAX_PATH], *tmp; + struct winetest_shared_data *data; + SIZE_T size = sizeof(*data); + const char *source_file; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING string; + void *addr = NULL; + HANDLE section; + + source_file = strrchr(file, '/'); + if (!source_file) source_file = strrchr(file, '\'); + if (!source_file) source_file = file; + else source_file++; + + strcpy(test_name, source_file); + if ((tmp = strrchr(test_name, '.'))) *tmp = 0; + + if (winetest_debug) + { + kprintf("%04x:%s: %d tests executed (%d marked as todo, %d %s), %d skipped.\n", + (DWORD)(DWORD_PTR)PsGetCurrentProcessId(), test_name, + successes + failures + todo_successes + todo_failures, + todo_successes, failures + todo_failures, + (failures + todo_failures != 1) ? "failures" : "failure", skipped ); + } + + RtlInitUnicodeString(&string, L"\BaseNamedObjects\winetest_driver_section"); + /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */ + InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL); + + if (!ZwOpenSection(§ion, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr)) + { + if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr, + 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE)) + { + data = addr; + + InterlockedExchangeAdd(&data->failures, failures); + InterlockedExchangeAdd(&data->todo_failures, todo_failures); + + ZwUnmapViewOfSection(NtCurrentProcess(), addr); + } + ZwClose(section); + } + + ZwClose(okfile); +} + +static inline void winetest_print_context( const char *msgtype ) +{ + struct tls_data *data = get_tls_data(); + unsigned int i; + + winetest_printf( "%s", msgtype ); + for (i = 0; i < data->context_count; ++i) + kprintf( "%s: ", data->context[i] ); +} + +static inline LONG winetest_add_line( void ) +{ + struct tls_data *data; + int index, count; + + if (winetest_debug > 1) + return 0; + + data = get_tls_data(); + index = data->current_line % ARRAY_SIZE(line_counters); + count = InterlockedIncrement(line_counters + index) - 1; + if (count == winetest_mute_threshold) + winetest_printf( "Line has been silenced after %d occurrences\n", winetest_mute_threshold ); + + return count; +} + +static inline int winetest_vok( int condition, const char *msg, __ms_va_list args ) +{ + struct tls_data *data = get_tls_data(); + + if (data->todo_level) + { + if (condition) + { + winetest_print_context( "Test succeeded inside todo block: " ); + kvprintf(msg, args); + InterlockedIncrement(&todo_failures); + return 0; + } + else + { + if (!winetest_debug || + winetest_add_line() < winetest_mute_threshold) + { + if (winetest_debug > 0) + { + winetest_print_context( "Test marked todo: " ); + kvprintf(msg, args); + } + InterlockedIncrement(&todo_successes); + } + else + InterlockedIncrement(&muted_todo_successes); + return 1; + } + } + else + { + if (!condition) + { + winetest_print_context( "Test failed: " ); + kvprintf(msg, args); + InterlockedIncrement(&failures); + return 0; + } + else + { + if (winetest_report_success) + winetest_printf("Test succeeded\n"); + InterlockedIncrement(&successes); + return 1; + } + } +} + +static inline void WINAPIV winetest_ok( int condition, const char *msg, ... ) __WINE_PRINTF_ATTR(2,3); +static inline void WINAPIV winetest_ok( int condition, const char *msg, ... ) +{ + __ms_va_list args; + __ms_va_start(args, msg); + winetest_vok(condition, msg, args); + __ms_va_end(args); +} + +static inline void winetest_vskip( const char *msg, __ms_va_list args ) +{ + if (winetest_add_line() < winetest_mute_threshold) + { + winetest_print_context( "Tests skipped: " ); + kvprintf(msg, args); + InterlockedIncrement(&skipped); + } + else + InterlockedIncrement(&muted_skipped); +} + +static inline void WINAPIV winetest_skip( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); +static inline void WINAPIV winetest_skip( const char *msg, ... ) +{ + __ms_va_list args; + __ms_va_start(args, msg); + winetest_vskip(msg, args); + __ms_va_end(args); +} + +static inline void WINAPIV winetest_win_skip( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); +static inline void WINAPIV winetest_win_skip( const char *msg, ... ) +{ + __ms_va_list args; + __ms_va_start(args, msg); + if (running_under_wine) + winetest_vskip(msg, args); + else + winetest_vok(0, msg, args); + __ms_va_end(args); +} + +static inline void WINAPIV winetest_trace( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); +static inline void WINAPIV winetest_trace( const char *msg, ... ) +{ + __ms_va_list args; + + if (!winetest_debug) + return; + if (winetest_add_line() < winetest_mute_threshold) + { + winetest_print_context( "" ); + __ms_va_start(args, msg); + kvprintf( msg, args ); + __ms_va_end(args); + } + else + InterlockedIncrement(&muted_traces); +} + +static inline void winetest_start_todo( int is_todo ) +{ + struct tls_data *data = get_tls_data(); + data->todo_level = (data->todo_level << 1) | (is_todo != 0); + data->todo_do_loop=1; +} + +static inline int winetest_loop_todo(void) +{ + struct tls_data *data = get_tls_data(); + int do_loop=data->todo_do_loop; + data->todo_do_loop=0; + return do_loop; +} + +static inline void winetest_end_todo(void) +{ + struct tls_data *data = get_tls_data(); + data->todo_level >>= 1; +} + +static inline void WINAPIV winetest_push_context( const char *fmt, ... ) __WINE_PRINTF_ATTR(1, 2); +static inline void WINAPIV winetest_push_context( const char *fmt, ... ) +{ + struct tls_data *data = get_tls_data(); + __ms_va_list valist; + + if (data->context_count < ARRAY_SIZE(data->context)) + { + __ms_va_start(valist, fmt); + vsnprintf( data->context[data->context_count], sizeof(data->context[data->context_count]), fmt, valist ); + __ms_va_end(valist); + data->context[data->context_count][sizeof(data->context[data->context_count]) - 1] = 0; + } + ++data->context_count; +} + +static inline void winetest_pop_context(void) +{ + struct tls_data *data = get_tls_data(); + + if (data->context_count) + --data->context_count; +} + +static inline int broken(int condition) +{ + return !running_under_wine && condition; +} + +#ifdef WINETEST_NO_LINE_NUMBERS +# define subtest_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_subtest +# define ignore_exceptions_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ignore_exceptions +# define ok_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ok +# define skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_skip +# define win_skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_win_skip +# define trace_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_trace +# define wait_child_process_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_wait_child_process +#else +# define subtest_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_subtest +# define ignore_exceptions_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ignore_exceptions +# define ok_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ok +# define skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_skip +# define win_skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_win_skip +# define trace_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_trace +# define wait_child_process_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_wait_child_process +#endif + +#define ok ok_(__FILE__, __LINE__) +#define skip skip_(__FILE__, __LINE__) +#define trace trace_(__FILE__, __LINE__) +#define win_skip win_skip_(__FILE__, __LINE__) + +#define todo_if(is_todo) for (winetest_start_todo(is_todo); \ + winetest_loop_todo(); \ + winetest_end_todo()) +#define todo_wine todo_if(running_under_wine) +#define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine) + +#endif /* __WINE_WINE_TEST_H */ + +#endif /* __WINE_WINE_TEST_DRIVER_H */
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntoskrnl.exe/tests/Makefile.in | 2 +- dlls/ntoskrnl.exe/tests/driver.c | 2 +- dlls/ntoskrnl.exe/tests/driver_hid.c | 2 +- dlls/ntoskrnl.exe/tests/driver_netio.c | 3 +- dlls/ntoskrnl.exe/tests/driver_pnp.c | 2 +- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 571 +------------------------ dlls/ntoskrnl.exe/tests/utils.h | 445 ------------------- 7 files changed, 26 insertions(+), 1001 deletions(-) delete mode 100644 dlls/ntoskrnl.exe/tests/utils.h
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in index 85a6925138a..3554998985b 100644 --- a/dlls/ntoskrnl.exe/tests/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = ntoskrnl.exe -IMPORTS = advapi32 crypt32 newdev setupapi user32 wintrust ws2_32 hid +IMPORTS = winetest uuid advapi32 crypt32 newdev setupapi user32 wintrust ws2_32 hid
driver_IMPORTS = winecrt0 ntoskrnl hal driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index 0d40053b0e6..e0a3db410cb 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -35,7 +35,7 @@
#include "driver.h"
-#include "utils.h" +#include "wine/test_driver.h"
/* memcmp() isn't exported from ntoskrnl on i386 */ static int kmemcmp( const void *ptr1, const void *ptr2, size_t n ) diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.c b/dlls/ntoskrnl.exe/tests/driver_hid.c index ed0767877ac..3697859be8f 100644 --- a/dlls/ntoskrnl.exe/tests/driver_hid.c +++ b/dlls/ntoskrnl.exe/tests/driver_hid.c @@ -35,7 +35,7 @@ #include "wine/list.h"
#include "driver.h" -#include "utils.h" +#include "wine/test_driver.h"
static UNICODE_STRING control_symlink;
diff --git a/dlls/ntoskrnl.exe/tests/driver_netio.c b/dlls/ntoskrnl.exe/tests/driver_netio.c index 4ebacc7cf14..c523912127d 100644 --- a/dlls/ntoskrnl.exe/tests/driver_netio.c +++ b/dlls/ntoskrnl.exe/tests/driver_netio.c @@ -33,8 +33,7 @@ #include "ddk/wsk.h"
#include "driver.h" - -#include "utils.h" +#include "wine/test_driver.h"
static DRIVER_OBJECT *driver_obj; static DEVICE_OBJECT *device_obj; diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index aa078ab0b2f..78f7a51ff76 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -32,7 +32,7 @@ #include "wine/list.h"
#include "driver.h" -#include "utils.h" +#include "wine/test_driver.h"
static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}}; static const GUID child_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}}; diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index dc10497caee..fde0c970bf7 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -36,6 +36,7 @@ #include "setupapi.h" #include "cfgmgr32.h" #include "newdev.h" +#include "objbase.h" #include "dbt.h" #include "initguid.h" #include "devguid.h" @@ -43,17 +44,14 @@ #include "ddk/hidsdi.h" #include "ddk/hidpi.h" #include "wine/test.h" +#include "wine/test_driver.h" #include "wine/heap.h" #include "wine/mssign.h"
#include "driver.h"
-static const GUID GUID_NULL; - static HANDLE device;
-static struct test_data *test_data; - static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *); static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *); static BOOL (WINAPI *pCancelIoEx)(HANDLE, OVERLAPPED *); @@ -85,169 +83,7 @@ static void load_resource(const WCHAR *name, WCHAR *filename) CloseHandle( file ); }
-struct testsign_context -{ - HCRYPTPROV provider; - const CERT_CONTEXT *cert, *root_cert, *publisher_cert; - HCERTSTORE root_store, publisher_store; -}; - -static BOOL testsign_create_cert(struct testsign_context *ctx) -{ - BYTE encoded_name[100], encoded_key_id[200], public_key_info_buffer[1000]; - WCHAR container_name[26]; - BYTE hash_buffer[16], cert_buffer[1000], provider_nameA[100], serial[16]; - CERT_PUBLIC_KEY_INFO *public_key_info = (CERT_PUBLIC_KEY_INFO *)public_key_info_buffer; - CRYPT_KEY_PROV_INFO provider_info = {0}; - CRYPT_ALGORITHM_IDENTIFIER algid = {0}; - CERT_AUTHORITY_KEY_ID_INFO key_info; - CERT_INFO cert_info = {0}; - WCHAR provider_nameW[100]; - CERT_EXTENSION extension; - HCRYPTKEY key; - DWORD size; - BOOL ret; - - memset(ctx, 0, sizeof(*ctx)); - - srand(time(NULL)); - swprintf(container_name, ARRAY_SIZE(container_name), L"wine_testsign%u", rand()); - - ret = CryptAcquireContextW(&ctx->provider, container_name, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET); - ok(ret, "Failed to create container, error %#x\n", GetLastError()); - - ret = CryptGenKey(ctx->provider, AT_SIGNATURE, CRYPT_EXPORTABLE, &key); - ok(ret, "Failed to create key, error %#x\n", GetLastError()); - ret = CryptDestroyKey(key); - ok(ret, "Failed to destroy key, error %#x\n", GetLastError()); - ret = CryptGetUserKey(ctx->provider, AT_SIGNATURE, &key); - ok(ret, "Failed to get user key, error %#x\n", GetLastError()); - ret = CryptDestroyKey(key); - ok(ret, "Failed to destroy key, error %#x\n", GetLastError()); - - size = sizeof(encoded_name); - ret = CertStrToNameA(X509_ASN_ENCODING, "CN=winetest_cert", CERT_X500_NAME_STR, NULL, encoded_name, &size, NULL); - ok(ret, "Failed to convert name, error %#x\n", GetLastError()); - key_info.CertIssuer.cbData = size; - key_info.CertIssuer.pbData = encoded_name; - - size = sizeof(public_key_info_buffer); - ret = CryptExportPublicKeyInfo(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, public_key_info, &size); - ok(ret, "Failed to export public key, error %#x\n", GetLastError()); - cert_info.SubjectPublicKeyInfo = *public_key_info; - - size = sizeof(hash_buffer); - ret = CryptHashPublicKeyInfo(ctx->provider, CALG_MD5, 0, X509_ASN_ENCODING, public_key_info, hash_buffer, &size); - ok(ret, "Failed to hash public key, error %#x\n", GetLastError()); - - key_info.KeyId.cbData = size; - key_info.KeyId.pbData = hash_buffer; - - RtlGenRandom(serial, sizeof(serial)); - key_info.CertSerialNumber.cbData = sizeof(serial); - key_info.CertSerialNumber.pbData = serial; - - size = sizeof(encoded_key_id); - ret = CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &key_info, encoded_key_id, &size); - ok(ret, "Failed to convert name, error %#x\n", GetLastError()); - - extension.pszObjId = (char *)szOID_AUTHORITY_KEY_IDENTIFIER; - extension.fCritical = TRUE; - extension.Value.cbData = size; - extension.Value.pbData = encoded_key_id; - - cert_info.dwVersion = CERT_V3; - cert_info.SerialNumber = key_info.CertSerialNumber; - cert_info.SignatureAlgorithm.pszObjId = (char *)szOID_RSA_SHA1RSA; - cert_info.Issuer = key_info.CertIssuer; - GetSystemTimeAsFileTime(&cert_info.NotBefore); - GetSystemTimeAsFileTime(&cert_info.NotAfter); - cert_info.NotAfter.dwHighDateTime += 1; - cert_info.Subject = key_info.CertIssuer; - cert_info.cExtension = 1; - cert_info.rgExtension = &extension; - algid.pszObjId = (char *)szOID_RSA_SHA1RSA; - size = sizeof(cert_buffer); - ret = CryptSignAndEncodeCertificate(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, - X509_CERT_TO_BE_SIGNED, &cert_info, &algid, NULL, cert_buffer, &size); - ok(ret, "Failed to create certificate, error %#x\n", GetLastError()); - - ctx->cert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_buffer, size); - ok(!!ctx->cert, "Failed to create context, error %#x\n", GetLastError()); - - size = sizeof(provider_nameA); - ret = CryptGetProvParam(ctx->provider, PP_NAME, provider_nameA, &size, 0); - ok(ret, "Failed to get prov param, error %#x\n", GetLastError()); - MultiByteToWideChar(CP_ACP, 0, (char *)provider_nameA, -1, provider_nameW, ARRAY_SIZE(provider_nameW)); - - provider_info.pwszContainerName = (WCHAR *)container_name; - provider_info.pwszProvName = provider_nameW; - provider_info.dwProvType = PROV_RSA_FULL; - provider_info.dwKeySpec = AT_SIGNATURE; - ret = CertSetCertificateContextProperty(ctx->cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provider_info); - ok(ret, "Failed to set provider info, error %#x\n", GetLastError()); - - ctx->root_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "root"); - if (!ctx->root_store && GetLastError() == ERROR_ACCESS_DENIED) - { - skip("Failed to open root store.\n"); - - ret = CertFreeCertificateContext(ctx->cert); - ok(ret, "Failed to free certificate, error %u\n", GetLastError()); - ret = CryptReleaseContext(ctx->provider, 0); - ok(ret, "failed to release context, error %u\n", GetLastError()); - - return FALSE; - } - ok(!!ctx->root_store, "Failed to open store, error %u\n", GetLastError()); - ret = CertAddCertificateContextToStore(ctx->root_store, ctx->cert, CERT_STORE_ADD_ALWAYS, &ctx->root_cert); - if (!ret && GetLastError() == ERROR_ACCESS_DENIED) - { - skip("Failed to add self-signed certificate to store.\n"); - - ret = CertFreeCertificateContext(ctx->cert); - ok(ret, "Failed to free certificate, error %u\n", GetLastError()); - ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); - ok(ret, "Failed to close store, error %u\n", GetLastError()); - ret = CryptReleaseContext(ctx->provider, 0); - ok(ret, "failed to release context, error %u\n", GetLastError()); - - return FALSE; - } - ok(ret, "Failed to add certificate, error %u\n", GetLastError()); - - ctx->publisher_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, - CERT_SYSTEM_STORE_LOCAL_MACHINE, "trustedpublisher"); - ok(!!ctx->publisher_store, "Failed to open store, error %u\n", GetLastError()); - ret = CertAddCertificateContextToStore(ctx->publisher_store, ctx->cert, - CERT_STORE_ADD_ALWAYS, &ctx->publisher_cert); - ok(ret, "Failed to add certificate, error %u\n", GetLastError()); - - return TRUE; -} - -static void testsign_cleanup(struct testsign_context *ctx) -{ - BOOL ret; - - ret = CertFreeCertificateContext(ctx->cert); - ok(ret, "Failed to free certificate, error %u\n", GetLastError()); - - ret = CertDeleteCertificateFromStore(ctx->root_cert); - ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); - ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); - ok(ret, "Failed to close store, error %u\n", GetLastError()); - - ret = CertDeleteCertificateFromStore(ctx->publisher_cert); - ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); - ret = CertCloseStore(ctx->publisher_store, CERT_CLOSE_STORE_CHECK_FLAG); - ok(ret, "Failed to close store, error %u\n", GetLastError()); - - ret = CryptReleaseContext(ctx->provider, 0); - ok(ret, "failed to release context, error %u\n", GetLastError()); -} - -static void testsign_sign(struct testsign_context *ctx, const WCHAR *filename) +static void testsign_sign(struct winetest_driver_context *ctx, const WCHAR *filename) { SIGNER_ATTR_AUTHCODE authcode = {sizeof(authcode)}; SIGNER_SIGNATURE_INFO signature = {sizeof(signature)}; @@ -294,7 +130,7 @@ static void unload_driver(SC_HANDLE service) CloseServiceHandle(service); }
-static SC_HANDLE load_driver(struct testsign_context *ctx, WCHAR *filename, +static SC_HANDLE load_driver(struct winetest_driver_context *ctx, WCHAR *filename, const WCHAR *resname, const WCHAR *driver_name) { SC_HANDLE manager, service; @@ -367,28 +203,6 @@ static BOOL start_driver(HANDLE service, BOOL vista_plus) return TRUE; }
-static HANDLE okfile; - -static void cat_okfile(void) -{ - char buffer[512]; - DWORD size; - - SetFilePointer(okfile, 0, NULL, FILE_BEGIN); - - do - { - ReadFile(okfile, buffer, sizeof(buffer), &size, NULL); - printf("%.*s", size, buffer); - } while (size == sizeof(buffer)); - - SetFilePointer(okfile, 0, NULL, FILE_BEGIN); - SetEndOfFile(okfile); - - winetest_add_failures(InterlockedExchange(&test_data->failures, 0)); - winetest_add_failures(InterlockedExchange(&test_data->todo_failures, 0)); -} - static ULONG64 modified_value;
static void main_test(void) @@ -1127,7 +941,7 @@ static void test_object_info(void) CloseHandle(file); }
-static void test_driver3(struct testsign_context *ctx) +static void test_driver3(struct winetest_driver_context *ctx) { WCHAR filename[MAX_PATH]; SC_HANDLE service; @@ -1207,7 +1021,7 @@ static DWORD WINAPI wsk_test_thread(void *parameter) return TRUE; }
-static void test_driver_netio(struct testsign_context *ctx) +static void test_driver_netio(struct winetest_driver_context *ctx) { WCHAR filename[MAX_PATH]; SC_HANDLE service; @@ -1236,110 +1050,7 @@ static void test_driver_netio(struct testsign_context *ctx) ret = DeleteFileW(filename); ok(ret, "DeleteFile failed: %u\n", GetLastError());
- cat_okfile(); -} - -#ifdef __i386__ -#define EXT "x86" -#elif defined(__x86_64__) -#define EXT "amd64" -#elif defined(__arm__) -#define EXT "arm" -#elif defined(__aarch64__) -#define EXT "arm64" -#else -#define EXT -#endif - -static const char inf_text[] = - "[Version]\n" - "Signature=$Chicago$\n" - "ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}\n" - "CatalogFile=winetest.cat\n" - "DriverVer=09/21/2006,6.0.5736.1\n" - - "[Manufacturer]\n" - "Wine=mfg_section,NT" EXT "\n" - - "[mfg_section.NT" EXT "]\n" - "Wine test root driver=device_section,test_hardware_id\n" - - "[device_section.NT" EXT "]\n" - "CopyFiles=file_section\n" - - "[device_section.NT" EXT ".Services]\n" - "AddService=winetest,0x2,svc_section\n" - - "[file_section]\n" - "winetest.sys\n" - - "[SourceDisksFiles]\n" - "winetest.sys=1\n" - - "[SourceDisksNames]\n" - "1=,winetest.sys\n" - - "[DestinationDirs]\n" - "DefaultDestDir=12\n" - - "[svc_section]\n" - "ServiceBinary=%12%\winetest.sys\n" - "ServiceType=1\n" - "StartType=3\n" - "ErrorControl=1\n" - "LoadOrderGroup=Extended Base\n" - "DisplayName="winetest bus driver"\n" - "; they don't sleep anymore, on the beach\n"; - -static void add_file_to_catalog(HANDLE catalog, const WCHAR *file) -{ - SIP_SUBJECTINFO subject_info = {sizeof(SIP_SUBJECTINFO)}; - SIP_INDIRECT_DATA *indirect_data; - const WCHAR *filepart = file; - CRYPTCATMEMBER *member; - WCHAR hash_buffer[100]; - GUID subject_guid; - unsigned int i; - DWORD size; - BOOL ret; - - ret = CryptSIPRetrieveSubjectGuidForCatalogFile(file, NULL, &subject_guid); - todo_wine ok(ret, "Failed to get subject guid, error %u\n", GetLastError()); - - size = 0; - subject_info.pgSubjectType = &subject_guid; - subject_info.pwsFileName = file; - subject_info.DigestAlgorithm.pszObjId = (char *)szOID_OIWSEC_sha1; - subject_info.dwFlags = SPC_INC_PE_RESOURCES_FLAG | SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG | SPC_EXC_PE_PAGE_HASHES_FLAG | 0x10000; - ret = CryptSIPCreateIndirectData(&subject_info, &size, NULL); - todo_wine ok(ret, "Failed to get indirect data size, error %u\n", GetLastError()); - - indirect_data = malloc(size); - ret = CryptSIPCreateIndirectData(&subject_info, &size, indirect_data); - todo_wine ok(ret, "Failed to get indirect data, error %u\n", GetLastError()); - if (ret) - { - memset(hash_buffer, 0, sizeof(hash_buffer)); - for (i = 0; i < indirect_data->Digest.cbData; ++i) - swprintf(&hash_buffer[i * 2], 2, L"%02X", indirect_data->Digest.pbData[i]); - - member = CryptCATPutMemberInfo(catalog, (WCHAR *)file, - hash_buffer, &subject_guid, 0, size, (BYTE *)indirect_data); - ok(!!member, "Failed to write member, error %u\n", GetLastError()); - - if (wcsrchr(file, '\')) - filepart = wcsrchr(file, '\') + 1; - - ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"File", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - (wcslen(filepart) + 1) * 2, (BYTE *)filepart); - ok(ret, "Failed to write attr, error %u\n", GetLastError()); - - ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"OSAttr", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - sizeof(L"2:6.0"), (BYTE *)L"2:6.0"); - ok(ret, "Failed to write attr, error %u\n", GetLastError()); - } + winetest_driver_check_failures(); }
static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}}; @@ -1698,131 +1409,12 @@ static void test_pnp_devices(void) UnregisterClassA("ntoskrnl_test_wc", GetModuleHandleA(NULL)); }
-static void test_pnp_driver(struct testsign_context *ctx) +static void test_pnp_driver(struct winetest_driver_context *ctx) { - static const char hardware_id[] = "test_hardware_id\0"; - char path[MAX_PATH], dest[MAX_PATH], *filepart; - SP_DEVINFO_DATA device = {sizeof(device)}; - char cwd[MAX_PATH], tempdir[MAX_PATH]; - WCHAR driver_filename[MAX_PATH]; - SC_HANDLE manager, service; - BOOL ret, need_reboot; - HANDLE catalog, file; - unsigned int i; - HDEVINFO set; - FILE *f; - - GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); - GetTempPathA(ARRAY_SIZE(tempdir), tempdir); - SetCurrentDirectoryA(tempdir); - - load_resource(L"driver_pnp.dll", driver_filename); - ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); - ok(ret, "failed to move file, error %u\n", GetLastError()); - - f = fopen("winetest.inf", "w"); - ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); - fputs(inf_text, f); - fclose(f); - - /* Create the catalog file. */ - - catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); - ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#x\n", GetLastError()); - - ret = !!CryptCATPutCatAttrInfo(catalog, (WCHAR *)L"HWID1", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - sizeof(L"test_hardware_id"), (BYTE *)L"test_hardware_id"); - todo_wine ok(ret, "failed to add attribute, error %#x\n", GetLastError()); - - ret = !!CryptCATPutCatAttrInfo(catalog, (WCHAR *)L"OS", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - sizeof(L"VistaX64"), (BYTE *)L"VistaX64"); - todo_wine ok(ret, "failed to add attribute, error %#x\n", GetLastError()); - - add_file_to_catalog(catalog, L"winetest.sys"); - add_file_to_catalog(catalog, L"winetest.inf"); - - ret = CryptCATPersistStore(catalog); - todo_wine ok(ret, "Failed to write catalog, error %u\n", GetLastError()); - - ret = CryptCATClose(catalog); - ok(ret, "Failed to close catalog, error %u\n", GetLastError()); - - testsign_sign(ctx, L"winetest.cat"); - - /* Install the driver. */ - - set = SetupDiCreateDeviceInfoList(NULL, NULL); - ok(set != INVALID_HANDLE_VALUE, "failed to create device list, error %#x\n", GetLastError()); - - ret = SetupDiCreateDeviceInfoA(set, "root\winetest\0", &GUID_NULL, NULL, NULL, 0, &device); - ok(ret, "failed to create device, error %#x\n", GetLastError()); - - ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID, - (const BYTE *)hardware_id, sizeof(hardware_id) ); - ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError()); - - ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); - ok(ret, "failed to register device, error %#x\n", GetLastError()); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = UpdateDriverForPlugAndPlayDevicesA(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); - ok(ret, "failed to install device, error %#x\n", GetLastError()); - ok(!need_reboot, "expected no reboot necessary\n"); - - /* Tests. */ - + if (!winetest_driver_start(ctx, L"driver_pnp.dll")) + return; test_pnp_devices(); - - /* Clean up. */ - - ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); - ok(ret, "failed to remove device, error %#x\n", GetLastError()); - - file = CreateFileA("\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); - ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); - - ret = SetupDiDestroyDeviceInfoList(set); - ok(ret, "failed to destroy set, error %#x\n", GetLastError()); - - set = SetupDiGetClassDevsA(NULL, "wine", NULL, DIGCF_ALLCLASSES); - ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#x\n", GetLastError()); - - for (i = 0; SetupDiEnumDeviceInfo(set, i, &device); ++i) - { - ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); - ok(ret, "failed to remove device, error %#x\n", GetLastError()); - } - - /* Windows stops the service but does not delete it. */ - manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); - ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); - service = OpenServiceA(manager, "winetest", SERVICE_STOP | DELETE); - ok(!!service, "failed to open service, error %u\n", GetLastError()); - unload_driver(service); - CloseServiceHandle(manager); - - cat_okfile(); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); - ok(ret, "Failed to copy INF, error %#x\n", GetLastError()); - ret = SetupUninstallOEMInfA(filepart, 0, NULL); - ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); - - ret = DeleteFileA("winetest.cat"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.inf"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.sys"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ - ret = DeleteFileA("C:/windows/system32/drivers/winetest.sys"); - ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); - - SetCurrentDirectoryA(cwd); + winetest_driver_stop(ctx); }
#define check_member_(file, line, val, exp, fmt, member) \ @@ -3295,24 +2887,10 @@ static void test_hid_device(DWORD report_id, DWORD polled) winetest_pop_context(); }
-static void test_hid_driver(struct testsign_context *ctx, DWORD report_id, DWORD polled) +static void test_hid_driver(struct winetest_driver_context *ctx, DWORD report_id, DWORD polled) { - static const char hardware_id[] = "test_hardware_id\0"; - char path[MAX_PATH], dest[MAX_PATH], *filepart; - SP_DEVINFO_DATA device = {sizeof(device)}; - char cwd[MAX_PATH], tempdir[MAX_PATH]; - WCHAR driver_filename[MAX_PATH]; - SC_HANDLE manager, service; - BOOL ret, need_reboot; - HANDLE catalog, file; LSTATUS status; - HDEVINFO set; HKEY hkey; - FILE *f; - - GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); - GetTempPathA(ARRAY_SIZE(tempdir), tempdir); - SetCurrentDirectoryA(tempdir);
status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"System\CurrentControlSet\Services\winetest", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL); ok(!status, "RegCreateKeyExW returned %#x\n", status); @@ -3323,104 +2901,19 @@ static void test_hid_driver(struct testsign_context *ctx, DWORD report_id, DWORD status = RegSetValueExW(hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled)); ok(!status, "RegSetValueExW returned %#x\n", status);
- load_resource(L"driver_hid.dll", driver_filename); - ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); - ok(ret, "failed to move file, error %u\n", GetLastError()); - - f = fopen("winetest.inf", "w"); - ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); - fputs(inf_text, f); - fclose(f); - - /* Create the catalog file. */ - - catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); - ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#x\n", GetLastError()); - - add_file_to_catalog(catalog, L"winetest.sys"); - add_file_to_catalog(catalog, L"winetest.inf"); - - ret = CryptCATPersistStore(catalog); - todo_wine ok(ret, "Failed to write catalog, error %u\n", GetLastError()); - - ret = CryptCATClose(catalog); - ok(ret, "Failed to close catalog, error %u\n", GetLastError()); - - testsign_sign(ctx, L"winetest.cat"); - - /* Install the driver. */ - - set = SetupDiCreateDeviceInfoList(NULL, NULL); - ok(set != INVALID_HANDLE_VALUE, "failed to create device list, error %#x\n", GetLastError()); - - ret = SetupDiCreateDeviceInfoA(set, "root\winetest\0", &GUID_NULL, NULL, NULL, 0, &device); - ok(ret, "failed to create device, error %#x\n", GetLastError()); - - ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID, - (const BYTE *)hardware_id, sizeof(hardware_id) ); - ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError()); - - ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); - ok(ret, "failed to register device, error %#x\n", GetLastError()); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = UpdateDriverForPlugAndPlayDevicesA(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); - ok(ret, "failed to install device, error %#x\n", GetLastError()); - ok(!need_reboot, "expected no reboot necessary\n"); - - /* Tests. */ - + if (!winetest_driver_start(ctx, L"driver_hid.dll")) + return; test_hid_device(report_id, polled); - - /* Clean up. */ - - ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); - ok(ret, "failed to remove device, error %#x\n", GetLastError()); - - file = CreateFileA("\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); - ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); - - ret = SetupDiDestroyDeviceInfoList(set); - ok(ret, "failed to destroy set, error %#x\n", GetLastError()); - - /* Windows stops the service but does not delete it. */ - manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); - ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); - service = OpenServiceA(manager, "winetest", SERVICE_STOP | DELETE); - ok(!!service, "failed to open service, error %u\n", GetLastError()); - unload_driver(service); - CloseServiceHandle(manager); - - cat_okfile(); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); - ok(ret, "Failed to copy INF, error %#x\n", GetLastError()); - ret = SetupUninstallOEMInfA(filepart, 0, NULL); - ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); - - ret = DeleteFileA("winetest.cat"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.inf"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.sys"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ - ret = DeleteFileA("C:/windows/system32/drivers/winetest.sys"); - ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); - - SetCurrentDirectoryA(cwd); + winetest_driver_stop(ctx); }
START_TEST(ntoskrnl) { WCHAR filename[MAX_PATH], filename2[MAX_PATH]; - struct testsign_context ctx; + struct winetest_driver_context ctx; SC_HANDLE service, service2; - BOOL ret, is_wow64; - HANDLE mapping; DWORD written; + BOOL ret;
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlDosPathNameToNtPathName_U"); pRtlFreeUnicodeString = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlFreeUnicodeString"); @@ -3428,29 +2921,11 @@ START_TEST(ntoskrnl) pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); pSetFileCompletionNotificationModes = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetFileCompletionNotificationModes"); - pSignerSign = (void *)GetProcAddress(LoadLibraryA("mssign32"), "SignerSign"); - - if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64) - { - skip("Running in WoW64.\n"); - return; - } + pSignerSign = (void *)GetProcAddress(LoadLibraryW(L"mssign32"), "SignerSign");
- if (!testsign_create_cert(&ctx)) + if (!winetest_driver_init(&ctx)) return;
- mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, sizeof(*test_data), "Global\winetest_ntoskrnl_section"); - ok(!!mapping, "got error %u\n", GetLastError()); - test_data = MapViewOfFile(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024); - test_data->running_under_wine = !strcmp(winetest_platform, "wine"); - test_data->winetest_report_success = winetest_report_success; - test_data->winetest_debug = winetest_debug; - - okfile = CreateFileA("C:\windows\winetest_ntoskrnl_okfile", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); - ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError()); - subtest("driver"); if (!(service = load_driver(&ctx, filename, L"driver.dll", L"WineTestDriver"))) goto out; @@ -3490,7 +2965,7 @@ START_TEST(ntoskrnl) ret = DeleteFileW(filename2); ok(ret, "DeleteFile failed: %u\n", GetLastError());
- cat_okfile(); + winetest_driver_check_failures();
test_driver3(&ctx); subtest("driver_netio"); @@ -3506,9 +2981,5 @@ START_TEST(ntoskrnl) test_hid_driver(&ctx, 1, TRUE);
out: - testsign_cleanup(&ctx); - UnmapViewOfFile(test_data); - CloseHandle(mapping); - CloseHandle(okfile); - DeleteFileA("C:\windows\winetest_ntoskrnl_okfile"); + winetest_driver_cleanup(&ctx); } diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h deleted file mode 100644 index de632c65b7c..00000000000 --- a/dlls/ntoskrnl.exe/tests/utils.h +++ /dev/null @@ -1,445 +0,0 @@ -/* - * ntoskrnl.exe testing framework - * - * Copyright 2015 Sebastian Lackner - * Copyright 2015 Michael Müller - * Copyright 2015 Christian Costa - * Copyright 2020 Paul Gofman for CodeWeavers - * Copyright 2020-2021 Zebediah Figura for CodeWeavers - * - * 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 <stdlib.h> -#include <windef.h> -#include <winbase.h> -#include <winternl.h> - -#include <ddk/wdm.h> - -#if !defined(__WINE_USE_MSVCRT) || defined(__MINGW32__) -#define __WINE_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args))) -#else -#define __WINE_PRINTF_ATTR(fmt,args) -#endif - -static HANDLE okfile; -static LONG successes; -static LONG failures; -static LONG skipped; -static LONG todo_successes; -static LONG todo_failures; -static LONG muted_traces; -static LONG muted_skipped; -static LONG muted_todo_successes; - -static int running_under_wine; -static int winetest_debug; -static int winetest_report_success; - -/* silence todos and skips above this threshold */ -static int winetest_mute_threshold = 42; - -/* counts how many times a given line printed a message */ -static LONG line_counters[16384]; - -/* The following data must be kept track of on a per-thread basis */ -struct tls_data -{ - HANDLE thread; - const char* current_file; /* file of current check */ - int current_line; /* line of current check */ - unsigned int todo_level; /* current todo nesting level */ - int todo_do_loop; - char *str_pos; /* position in debug buffer */ - char strings[2000]; /* buffer for debug strings */ - char context[8][128]; /* data to print before messages */ - unsigned int context_count; /* number of context prefixes */ -}; - -static KSPIN_LOCK tls_data_lock; -static struct tls_data tls_data_pool[128]; -static DWORD tls_data_count; - -static inline struct tls_data *get_tls_data(void) -{ - static struct tls_data tls_overflow; - struct tls_data *data; - HANDLE thread = PsGetCurrentThreadId(); - KIRQL irql; - - KeAcquireSpinLock(&tls_data_lock, &irql); - for (data = tls_data_pool; data != tls_data_pool + tls_data_count; ++data) - if (data->thread == thread) break; - if (data == tls_data_pool + ARRAY_SIZE(tls_data_pool)) - data = &tls_overflow; - else if (data == tls_data_pool + tls_data_count) - { - data->thread = thread; - data->str_pos = data->strings; - tls_data_count++; - } - KeReleaseSpinLock(&tls_data_lock, irql); - - return data; -} - -static inline void winetest_set_location( const char* file, int line ) -{ - struct tls_data *data = get_tls_data(); - data->current_file=strrchr(file,'/'); - if (data->current_file==NULL) - data->current_file=strrchr(file,'\'); - if (data->current_file==NULL) - data->current_file=file; - else - data->current_file++; - data->current_line=line; -} - -static inline void kvprintf(const char *format, __ms_va_list ap) -{ - struct tls_data *data = get_tls_data(); - IO_STATUS_BLOCK io; - int len = vsnprintf(data->strings, sizeof(data->strings), format, ap); - ZwWriteFile(okfile, NULL, NULL, NULL, &io, data->strings, len, NULL, NULL); -} - -static inline void WINAPIV kprintf(const char *format, ...) __WINE_PRINTF_ATTR(1,2); -static inline void WINAPIV kprintf(const char *format, ...) -{ - __ms_va_list valist; - - __ms_va_start(valist, format); - kvprintf(format, valist); - __ms_va_end(valist); -} - -static inline void WINAPIV winetest_printf( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); -static inline void WINAPIV winetest_printf( const char *msg, ... ) -{ - struct tls_data *data = get_tls_data(); - __ms_va_list valist; - - kprintf( "%s:%d: ", data->current_file, data->current_line ); - __ms_va_start( valist, msg ); - kvprintf( msg, valist ); - __ms_va_end( valist ); -} - -static inline NTSTATUS winetest_init(void) -{ - const struct test_data *data; - SIZE_T size = sizeof(*data); - OBJECT_ATTRIBUTES attr; - UNICODE_STRING string; - IO_STATUS_BLOCK io; - void *addr = NULL; - HANDLE section; - NTSTATUS ret; - - KeInitializeSpinLock(&tls_data_lock); - - RtlInitUnicodeString(&string, L"\BaseNamedObjects\winetest_ntoskrnl_section"); - /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */ - InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL); - if ((ret = ZwOpenSection(§ion, SECTION_MAP_READ, &attr))) - return ret; - - if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr, - 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY))) - { - ZwClose(section); - return ret; - } - data = addr; - running_under_wine = data->running_under_wine; - winetest_debug = data->winetest_debug; - winetest_report_success = data->winetest_report_success; - - ZwUnmapViewOfSection(NtCurrentProcess(), addr); - ZwClose(section); - - RtlInitUnicodeString(&string, L"\??\C:\windows\winetest_ntoskrnl_okfile"); - return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io, - FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); -} - -#define winetest_cleanup() winetest_cleanup_(__FILE__) -static inline void winetest_cleanup_(const char *file) -{ - char test_name[MAX_PATH], *tmp; - struct test_data *data; - SIZE_T size = sizeof(*data); - const char *source_file; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING string; - void *addr = NULL; - HANDLE section; - - source_file = strrchr(file, '/'); - if (!source_file) source_file = strrchr(file, '\'); - if (!source_file) source_file = file; - else source_file++; - - strcpy(test_name, source_file); - if ((tmp = strrchr(test_name, '.'))) *tmp = 0; - - if (winetest_debug) - { - kprintf("%04x:%s: %d tests executed (%d marked as todo, %d %s), %d skipped.\n", - (DWORD)(DWORD_PTR)PsGetCurrentProcessId(), test_name, - successes + failures + todo_successes + todo_failures, - todo_successes, failures + todo_failures, - (failures + todo_failures != 1) ? "failures" : "failure", skipped ); - } - - RtlInitUnicodeString(&string, L"\BaseNamedObjects\winetest_ntoskrnl_section"); - /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */ - InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL); - - if (!ZwOpenSection(§ion, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr)) - { - if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr, - 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE)) - { - data = addr; - - InterlockedExchangeAdd(&data->failures, failures); - InterlockedExchangeAdd(&data->todo_failures, todo_failures); - - ZwUnmapViewOfSection(NtCurrentProcess(), addr); - } - ZwClose(section); - } - - ZwClose(okfile); -} - -static inline void winetest_print_context( const char *msgtype ) -{ - struct tls_data *data = get_tls_data(); - unsigned int i; - - winetest_printf( "%s", msgtype ); - for (i = 0; i < data->context_count; ++i) - kprintf( "%s: ", data->context[i] ); -} - -static inline LONG winetest_add_line( void ) -{ - struct tls_data *data; - int index, count; - - if (winetest_debug > 1) - return 0; - - data = get_tls_data(); - index = data->current_line % ARRAY_SIZE(line_counters); - count = InterlockedIncrement(line_counters + index) - 1; - if (count == winetest_mute_threshold) - winetest_printf( "Line has been silenced after %d occurrences\n", winetest_mute_threshold ); - - return count; -} - -static inline int winetest_vok( int condition, const char *msg, __ms_va_list args ) -{ - struct tls_data *data = get_tls_data(); - - if (data->todo_level) - { - if (condition) - { - winetest_print_context( "Test succeeded inside todo block: " ); - kvprintf(msg, args); - InterlockedIncrement(&todo_failures); - return 0; - } - else - { - if (!winetest_debug || - winetest_add_line() < winetest_mute_threshold) - { - if (winetest_debug > 0) - { - winetest_print_context( "Test marked todo: " ); - kvprintf(msg, args); - } - InterlockedIncrement(&todo_successes); - } - else - InterlockedIncrement(&muted_todo_successes); - return 1; - } - } - else - { - if (!condition) - { - winetest_print_context( "Test failed: " ); - kvprintf(msg, args); - InterlockedIncrement(&failures); - return 0; - } - else - { - if (winetest_report_success) - winetest_printf("Test succeeded\n"); - InterlockedIncrement(&successes); - return 1; - } - } -} - -static inline void WINAPIV winetest_ok( int condition, const char *msg, ... ) __WINE_PRINTF_ATTR(2,3); -static inline void WINAPIV winetest_ok( int condition, const char *msg, ... ) -{ - __ms_va_list args; - __ms_va_start(args, msg); - winetest_vok(condition, msg, args); - __ms_va_end(args); -} - -static inline void winetest_vskip( const char *msg, __ms_va_list args ) -{ - if (winetest_add_line() < winetest_mute_threshold) - { - winetest_print_context( "Tests skipped: " ); - kvprintf(msg, args); - InterlockedIncrement(&skipped); - } - else - InterlockedIncrement(&muted_skipped); -} - -static inline void WINAPIV winetest_skip( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); -static inline void WINAPIV winetest_skip( const char *msg, ... ) -{ - __ms_va_list args; - __ms_va_start(args, msg); - winetest_vskip(msg, args); - __ms_va_end(args); -} - -static inline void WINAPIV winetest_win_skip( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); -static inline void WINAPIV winetest_win_skip( const char *msg, ... ) -{ - __ms_va_list args; - __ms_va_start(args, msg); - if (running_under_wine) - winetest_vskip(msg, args); - else - winetest_vok(0, msg, args); - __ms_va_end(args); -} - -static inline void WINAPIV winetest_trace( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2); -static inline void WINAPIV winetest_trace( const char *msg, ... ) -{ - __ms_va_list args; - - if (!winetest_debug) - return; - if (winetest_add_line() < winetest_mute_threshold) - { - winetest_print_context( "" ); - __ms_va_start(args, msg); - kvprintf( msg, args ); - __ms_va_end(args); - } - else - InterlockedIncrement(&muted_traces); -} - -static inline void winetest_start_todo( int is_todo ) -{ - struct tls_data *data = get_tls_data(); - data->todo_level = (data->todo_level << 1) | (is_todo != 0); - data->todo_do_loop=1; -} - -static inline int winetest_loop_todo(void) -{ - struct tls_data *data = get_tls_data(); - int do_loop=data->todo_do_loop; - data->todo_do_loop=0; - return do_loop; -} - -static inline void winetest_end_todo(void) -{ - struct tls_data *data = get_tls_data(); - data->todo_level >>= 1; -} - -static inline void WINAPIV winetest_push_context( const char *fmt, ... ) __WINE_PRINTF_ATTR(1, 2); -static inline void WINAPIV winetest_push_context( const char *fmt, ... ) -{ - struct tls_data *data = get_tls_data(); - __ms_va_list valist; - - if (data->context_count < ARRAY_SIZE(data->context)) - { - __ms_va_start(valist, fmt); - vsnprintf( data->context[data->context_count], sizeof(data->context[data->context_count]), fmt, valist ); - __ms_va_end(valist); - data->context[data->context_count][sizeof(data->context[data->context_count]) - 1] = 0; - } - ++data->context_count; -} - -static inline void winetest_pop_context(void) -{ - struct tls_data *data = get_tls_data(); - - if (data->context_count) - --data->context_count; -} - -static inline int broken(int condition) -{ - return !running_under_wine && condition; -} - -#ifdef WINETEST_NO_LINE_NUMBERS -# define subtest_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_subtest -# define ignore_exceptions_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ignore_exceptions -# define ok_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_ok -# define skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_skip -# define win_skip_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_win_skip -# define trace_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_trace -# define wait_child_process_(file, line) (winetest_set_location(file, 0), 0) ? (void)0 : winetest_wait_child_process -#else -# define subtest_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_subtest -# define ignore_exceptions_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ignore_exceptions -# define ok_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_ok -# define skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_skip -# define win_skip_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_win_skip -# define trace_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_trace -# define wait_child_process_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : winetest_wait_child_process -#endif - -#define ok ok_(__FILE__, __LINE__) -#define skip skip_(__FILE__, __LINE__) -#define trace trace_(__FILE__, __LINE__) -#define win_skip win_skip_(__FILE__, __LINE__) - -#define todo_if(is_todo) for (winetest_start_todo(is_todo); \ - winetest_loop_todo(); \ - winetest_end_todo()) -#define todo_wine todo_if(running_under_wine) -#define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine)