xref: /aosp_15_r20/external/angle/util/test_utils.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // system_utils: Defines common utility functions
8 
9 #include "util/test_utils.h"
10 
11 #include <EGL/egl.h>
12 #include <EGL/eglext.h>
13 
14 #include <cstring>
15 #include <fstream>
16 #include <iostream>
17 
18 namespace angle
19 {
20 
21 namespace
22 {
DeleteArg(int * argc,char ** argv,int argIndex)23 void DeleteArg(int *argc, char **argv, int argIndex)
24 {
25     // Shift the remainder of the argv list left by one.  Note that argv has (*argc + 1) elements,
26     // the last one always being NULL.  The following loop moves the trailing NULL element as well.
27     for (int index = argIndex; index < *argc; ++index)
28     {
29         argv[index] = argv[index + 1];
30     }
31     (*argc)--;
32 }
33 
GetSingleArg(const char * flag,int * argc,char ** argv,int argIndex,ArgHandling handling)34 const char *GetSingleArg(const char *flag,
35                          int *argc,
36                          char **argv,
37                          int argIndex,
38                          ArgHandling handling)
39 {
40     if (strstr(argv[argIndex], flag) == argv[argIndex])
41     {
42         const char *ptr = argv[argIndex] + strlen(flag);
43 
44         if (*ptr == '=')
45         {
46             if (handling == ArgHandling::Delete)
47             {
48                 DeleteArg(argc, argv, argIndex);
49             }
50             return ptr + 1;
51         }
52 
53         if (*ptr == '\0' && argIndex < *argc - 1)
54         {
55             ptr = argv[argIndex + 1];
56             if (handling == ArgHandling::Delete)
57             {
58                 DeleteArg(argc, argv, argIndex);
59                 DeleteArg(argc, argv, argIndex);
60             }
61             return ptr;
62         }
63     }
64 
65     return nullptr;
66 }
67 
68 using DisplayTypeInfo = std::pair<const char *, EGLint>;
69 
70 const DisplayTypeInfo kDisplayTypes[] = {
71     {"d3d9", EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE},
72     {"d3d11", EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE},
73     {"gl", EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE},
74     {"gles", EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE},
75     {"metal", EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE},
76     {"null", EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE},
77     {"swiftshader", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
78     {"vulkan", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
79     {"vulkan-null", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
80     {"webgpu", EGL_PLATFORM_ANGLE_TYPE_WEBGPU_ANGLE},
81 };
82 }  // anonymous namespace
83 
GetFileSize(const char * filePath,uint32_t * sizeOut)84 bool GetFileSize(const char *filePath, uint32_t *sizeOut)
85 {
86     std::ifstream stream(filePath);
87     if (!stream)
88     {
89         return false;
90     }
91 
92     stream.seekg(0, std::ios::end);
93     *sizeOut = static_cast<uint32_t>(stream.tellg());
94     return true;
95 }
96 
ReadEntireFileToString(const char * filePath,std::string * contentsOut)97 bool ReadEntireFileToString(const char *filePath, std::string *contentsOut)
98 {
99     std::ifstream stream(filePath);
100     if (!stream)
101     {
102         return false;
103     }
104 
105     stream.seekg(0, std::ios::end);
106     contentsOut->reserve(static_cast<unsigned int>(stream.tellg()));
107     stream.seekg(0, std::ios::beg);
108 
109     contentsOut->assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
110 
111     return true;
112 }
113 
114 // static
115 Process::~Process() = default;
116 
ProcessHandle()117 ProcessHandle::ProcessHandle() : mProcess(nullptr) {}
118 
ProcessHandle(Process * process)119 ProcessHandle::ProcessHandle(Process *process) : mProcess(process) {}
120 
ProcessHandle(const std::vector<const char * > & args,ProcessOutputCapture captureOutput)121 ProcessHandle::ProcessHandle(const std::vector<const char *> &args,
122                              ProcessOutputCapture captureOutput)
123     : mProcess(LaunchProcess(args, captureOutput))
124 {}
125 
~ProcessHandle()126 ProcessHandle::~ProcessHandle()
127 {
128     reset();
129 }
130 
ProcessHandle(ProcessHandle && other)131 ProcessHandle::ProcessHandle(ProcessHandle &&other) : mProcess(other.mProcess)
132 {
133     other.mProcess = nullptr;
134 }
135 
operator =(ProcessHandle && rhs)136 ProcessHandle &ProcessHandle::operator=(ProcessHandle &&rhs)
137 {
138     std::swap(mProcess, rhs.mProcess);
139     return *this;
140 }
141 
reset()142 void ProcessHandle::reset()
143 {
144     if (mProcess)
145     {
146         delete mProcess;
147         mProcess = nullptr;
148     }
149 }
150 
ParseIntArgWithHandling(const char * flag,int * argc,char ** argv,int argIndex,int * valueOut,ArgHandling handling)151 bool ParseIntArgWithHandling(const char *flag,
152                              int *argc,
153                              char **argv,
154                              int argIndex,
155                              int *valueOut,
156                              ArgHandling handling)
157 {
158     const char *value = GetSingleArg(flag, argc, argv, argIndex, handling);
159     if (!value)
160     {
161         return false;
162     }
163 
164     char *end            = nullptr;
165     const long longValue = strtol(value, &end, 10);
166 
167     if (*end != '\0')
168     {
169         printf("Error parsing integer flag value.\n");
170         exit(EXIT_FAILURE);
171     }
172 
173     if (longValue == LONG_MAX || longValue == LONG_MIN || static_cast<int>(longValue) != longValue)
174     {
175         printf("Overflow when parsing integer flag value.\n");
176         exit(EXIT_FAILURE);
177     }
178 
179     *valueOut = static_cast<int>(longValue);
180     // Note: return value is always false with ArgHandling::Preserve handling
181     return handling == ArgHandling::Delete;
182 }
183 
ParseIntArg(const char * flag,int * argc,char ** argv,int argIndex,int * valueOut)184 bool ParseIntArg(const char *flag, int *argc, char **argv, int argIndex, int *valueOut)
185 {
186     return ParseIntArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete);
187 }
188 
ParseFlag(const char * flag,int * argc,char ** argv,int argIndex,bool * flagOut)189 bool ParseFlag(const char *flag, int *argc, char **argv, int argIndex, bool *flagOut)
190 {
191     if (strcmp(flag, argv[argIndex]) == 0)
192     {
193         *flagOut = true;
194         DeleteArg(argc, argv, argIndex);
195         return true;
196     }
197     return false;
198 }
199 
ParseStringArg(const char * flag,int * argc,char ** argv,int argIndex,std::string * valueOut)200 bool ParseStringArg(const char *flag, int *argc, char **argv, int argIndex, std::string *valueOut)
201 {
202     const char *value = GetSingleArg(flag, argc, argv, argIndex, ArgHandling::Delete);
203     if (!value)
204     {
205         return false;
206     }
207 
208     *valueOut = value;
209     return true;
210 }
211 
ParseCStringArgWithHandling(const char * flag,int * argc,char ** argv,int argIndex,const char ** valueOut,ArgHandling handling)212 bool ParseCStringArgWithHandling(const char *flag,
213                                  int *argc,
214                                  char **argv,
215                                  int argIndex,
216                                  const char **valueOut,
217                                  ArgHandling handling)
218 {
219     const char *value = GetSingleArg(flag, argc, argv, argIndex, handling);
220     if (!value)
221     {
222         return false;
223     }
224 
225     *valueOut = value;
226     // Note: return value is always false with ArgHandling::Preserve handling
227     return handling == ArgHandling::Delete;
228 }
229 
ParseCStringArg(const char * flag,int * argc,char ** argv,int argIndex,const char ** valueOut)230 bool ParseCStringArg(const char *flag, int *argc, char **argv, int argIndex, const char **valueOut)
231 {
232     return ParseCStringArgWithHandling(flag, argc, argv, argIndex, valueOut, ArgHandling::Delete);
233 }
234 
AddArg(int * argc,char ** argv,const char * arg)235 void AddArg(int *argc, char **argv, const char *arg)
236 {
237     // This unsafe const_cast is necessary to work around gtest limitations.
238     argv[*argc]     = const_cast<char *>(arg);
239     argv[*argc + 1] = nullptr;
240     (*argc)++;
241 }
242 
GetPlatformANGLETypeFromArg(const char * useANGLEArg,uint32_t defaultPlatformType)243 uint32_t GetPlatformANGLETypeFromArg(const char *useANGLEArg, uint32_t defaultPlatformType)
244 {
245     if (!useANGLEArg)
246     {
247         return defaultPlatformType;
248     }
249 
250     for (const DisplayTypeInfo &displayTypeInfo : kDisplayTypes)
251     {
252         if (strcmp(displayTypeInfo.first, useANGLEArg) == 0)
253         {
254             std::cout << "Using ANGLE back-end API: " << displayTypeInfo.first << std::endl;
255             return displayTypeInfo.second;
256         }
257     }
258 
259     std::cout << "Unknown ANGLE back-end API: " << useANGLEArg << std::endl;
260     exit(EXIT_FAILURE);
261 }
262 
GetANGLEDeviceTypeFromArg(const char * useANGLEArg,uint32_t defaultDeviceType)263 uint32_t GetANGLEDeviceTypeFromArg(const char *useANGLEArg, uint32_t defaultDeviceType)
264 {
265     if (useANGLEArg)
266     {
267         if (strcmp(useANGLEArg, "swiftshader") == 0)
268         {
269             return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
270         }
271         if (strstr(useANGLEArg, "null") != 0)
272         {
273             return EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE;
274         }
275     }
276     return defaultDeviceType;
277 }
278 }  // namespace angle
279