vkd3d-shader/hlsl: Handle error instructions in add_shader_compilation().
[vkd3d.git] / tests / driver.c
blob4054f1c2f1882292d194caf691798498cc516366
1 /*
2 * Copyright 2023 Giovanni Mascellani for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdio.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <time.h>
24 #include <windows.h>
25 #include <shlobj.h>
27 #define TIMEOUT_MS (10 * 1000)
28 #define MAX_TIMEOUT_COUNT 3
30 enum program_result
32 PROGRAM_RESULT_SUCCESS,
33 PROGRAM_RESULT_TIMEOUT,
34 PROGRAM_RESULT_FAILURE,
37 static enum program_result run_program(const char *cmdline, const char *log_filename)
39 char cmdline2[1024], log_dirname[1024], *file_part;
40 enum program_result ret = PROGRAM_RESULT_SUCCESS;
41 HANDLE log = INVALID_HANDLE_VALUE;
42 SECURITY_ATTRIBUTES attrs = {0};
43 PROCESS_INFORMATION info = {0};
44 DWORD exit_code, wait_result;
45 STARTUPINFOA startup = {0};
46 int res;
48 strcpy(cmdline2, cmdline);
50 if (GetFullPathNameA(log_filename, sizeof(log_dirname), log_dirname, &file_part) == 0)
52 fprintf(stderr, "Cannot extract the directory name for path %s, last error %ld.\n", log_filename, GetLastError());
53 ret = PROGRAM_RESULT_FAILURE;
54 goto out;
56 *file_part = '\0';
58 res = SHCreateDirectoryExA(NULL, log_dirname, NULL);
59 if (res != ERROR_SUCCESS && res != ERROR_ALREADY_EXISTS)
61 fprintf(stderr, "Cannot create log directory %s, error %d.\n", log_dirname, res);
62 ret = PROGRAM_RESULT_FAILURE;
63 goto out;
66 attrs.nLength = sizeof(attrs);
67 attrs.bInheritHandle = TRUE;
69 log = CreateFileA(log_filename, GENERIC_WRITE, 0, &attrs, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
70 if (log == INVALID_HANDLE_VALUE)
72 fprintf(stderr, "Cannot create log file %s, last error %ld.\n", log_filename, GetLastError());
73 ret = PROGRAM_RESULT_FAILURE;
74 goto out;
77 startup.cb = sizeof(startup);
78 startup.dwFlags = STARTF_USESTDHANDLES;
79 startup.hStdInput = INVALID_HANDLE_VALUE;
80 startup.hStdOutput = log;
81 startup.hStdError = log;
83 if (!CreateProcessA(NULL, cmdline2, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info))
85 fprintf(stderr, "Cannot create process %s, last error %ld.\n", cmdline2, GetLastError());
86 ret = PROGRAM_RESULT_FAILURE;
87 goto out;
90 wait_result = WaitForSingleObject(info.hProcess, TIMEOUT_MS);
91 if (wait_result == WAIT_TIMEOUT)
93 fprintf(stderr, "Process timed out, terminating it.\n");
94 ret = PROGRAM_RESULT_TIMEOUT;
96 if (!TerminateProcess(info.hProcess, 1))
98 fprintf(stderr, "Cannot terminate process, last error %ld.\n", GetLastError());
99 goto out;
102 wait_result = WaitForSingleObject(info.hProcess, INFINITE);
105 if (wait_result != WAIT_OBJECT_0)
107 fprintf(stderr, "Cannot wait for process termination, last error %ld.\n", GetLastError());
108 ret = PROGRAM_RESULT_FAILURE;
109 goto out;
112 if (!GetExitCodeProcess(info.hProcess, &exit_code))
114 fprintf(stderr, "Cannot retrieve the process exit code, last error %ld.\n", GetLastError());
115 ret = PROGRAM_RESULT_FAILURE;
116 goto out;
119 ret = exit_code == 0 ? PROGRAM_RESULT_SUCCESS : PROGRAM_RESULT_FAILURE;
121 printf("%s: %s\n", ret == PROGRAM_RESULT_SUCCESS ? "PASS" : "FAIL", cmdline);
123 out:
124 if (info.hProcess && !CloseHandle(info.hProcess))
125 fprintf(stderr, "Cannot close process, last error %ld.\n", GetLastError());
126 if (info.hThread && !CloseHandle(info.hThread))
127 fprintf(stderr, "Cannot close thread, last error %ld.\n", GetLastError());
128 if (log != INVALID_HANDLE_VALUE && !CloseHandle(log))
129 fprintf(stderr, "Cannot close log file, last error %ld.\n", GetLastError());
131 return ret;
134 static bool run_tests_for_directory(const char *commit_dir)
136 char cmdline[1024], log_filename[1024], list_filename[1024], line[1024];
137 unsigned int success_count = 0, test_count = 0, timeout_count = 0;
138 const char *test_arch = getenv("TEST_ARCH");
139 enum program_result result;
140 FILE *list_file;
141 bool ret = true;
143 if (!test_arch)
144 test_arch = "64";
146 printf("\e[0Ksection_start:%I64d:commit_%s\r\e[0KBuilding commit %s\n",
147 (uint64_t)time(NULL), commit_dir, commit_dir);
149 sprintf(list_filename, "artifacts/%s/tests/shader_tests.txt", commit_dir);
150 list_file = fopen(list_filename, "r");
152 if (!list_file)
154 fprintf(stderr, "Cannot open list file %s, errno %d.\n", list_filename, errno);
155 ret = false;
157 else
159 while (fgets(line, sizeof(line), list_file) && timeout_count < MAX_TIMEOUT_COUNT)
161 size_t len = strlen(line);
163 if (line[len - 1] == '\n')
164 line[--len] = '\0';
166 sprintf(cmdline, "artifacts/%s/tests/shader_runner.cross%s.exe %s", commit_dir, test_arch, line);
168 /* Remove the .shader_test suffix. */
169 line[len - 12] = '\0';
170 sprintf(log_filename, "artifacts/%s/%s.log", commit_dir, line);
172 ++test_count;
173 result = run_program(cmdline, log_filename);
174 success_count += result == PROGRAM_RESULT_SUCCESS;
175 timeout_count += result == PROGRAM_RESULT_TIMEOUT;
178 fclose(list_file);
181 sprintf(list_filename, "artifacts/%s/tests/crosstests.txt", commit_dir);
182 list_file = fopen(list_filename, "r");
184 if (!list_file)
186 fprintf(stderr, "Cannot open list file %s, errno %d.\n", list_filename, errno);
187 ret = false;
189 else
191 while (fgets(line, sizeof(line), list_file) && timeout_count < MAX_TIMEOUT_COUNT)
193 size_t len = strlen(line);
195 if (line[len - 1] == '\n')
196 line[len - 1] = '\0';
198 sprintf(cmdline, "artifacts/%s/%s.cross%s.exe", commit_dir, line, test_arch);
199 sprintf(log_filename, "artifacts/%s/%s.log", commit_dir, line);
200 ++test_count;
201 result = run_program(cmdline, log_filename);
202 success_count += result == PROGRAM_RESULT_SUCCESS;
203 timeout_count += result == PROGRAM_RESULT_TIMEOUT;
206 fclose(list_file);
209 if (timeout_count >= MAX_TIMEOUT_COUNT)
210 fprintf(stderr, "Too many timeouts, aborting tests.\n");
212 printf("=======\n");
213 printf("Summary\n");
214 printf("=======\n");
216 printf("# TOTAL: %u\n", test_count);
217 printf("# PASS: %u\n", success_count);
218 printf("# FAIL: %u\n", test_count - success_count);
220 if (test_count != success_count)
222 HANDLE handle;
224 handle = CreateFileA("pipeline_failed", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
225 if (handle == INVALID_HANDLE_VALUE)
227 fprintf(stderr, "Cannot create failure file, last error %ld.\n", GetLastError());
228 ret = false;
230 else
232 if (!CloseHandle(handle))
233 fprintf(stderr, "Cannot close failure file, last error %ld.\n", GetLastError());
237 printf("\e[0Ksection_end:%I64d:commit_%s\r\e[0K\n",
238 (uint64_t)time(NULL), commit_dir);
240 return ret;
243 int wmain(int argc, WCHAR **wargv)
245 char commit_num[16], commit_hash[16], commit_dir[16];
247 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
249 if (argc != 3)
251 fprintf(stderr, "Call with commit number and hash.\n");
252 return 1;
255 WideCharToMultiByte(CP_ACP, 0, wargv[1], -1, commit_num, sizeof(commit_num), NULL, NULL);
256 WideCharToMultiByte(CP_ACP, 0, wargv[2], -1, commit_hash, sizeof(commit_hash), NULL, NULL);
257 commit_num[sizeof(commit_num) - 1] = '\0';
258 commit_hash[sizeof(commit_hash) - 1] = '\0';
259 snprintf(commit_dir, sizeof(commit_dir), "%03d-%s", atoi(commit_num), commit_hash);
260 commit_dir[sizeof(commit_dir) - 1] = '\0';
262 return !run_tests_for_directory(commit_dir);