1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker
6*8975f5c5SAndroid Build Coastguard Worker // system_utils_unittest.cpp: Unit tests for ANGLE's system utility functions
7*8975f5c5SAndroid Build Coastguard Worker
8*8975f5c5SAndroid Build Coastguard Worker #include "gmock/gmock.h"
9*8975f5c5SAndroid Build Coastguard Worker #include "gtest/gtest.h"
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard Worker #include "common/mathutil.h"
12*8975f5c5SAndroid Build Coastguard Worker #include "common/system_utils.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "util/test_utils.h"
14*8975f5c5SAndroid Build Coastguard Worker
15*8975f5c5SAndroid Build Coastguard Worker #include <fstream>
16*8975f5c5SAndroid Build Coastguard Worker #include <sstream>
17*8975f5c5SAndroid Build Coastguard Worker #include <vector>
18*8975f5c5SAndroid Build Coastguard Worker
19*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_POSIX)
20*8975f5c5SAndroid Build Coastguard Worker # include <signal.h>
21*8975f5c5SAndroid Build Coastguard Worker #endif
22*8975f5c5SAndroid Build Coastguard Worker
23*8975f5c5SAndroid Build Coastguard Worker using namespace angle;
24*8975f5c5SAndroid Build Coastguard Worker
25*8975f5c5SAndroid Build Coastguard Worker namespace
26*8975f5c5SAndroid Build Coastguard Worker {
27*8975f5c5SAndroid Build Coastguard Worker // Test getting the executable path
TEST(SystemUtils,ExecutablePath)28*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ExecutablePath)
29*8975f5c5SAndroid Build Coastguard Worker {
30*8975f5c5SAndroid Build Coastguard Worker // TODO: fuchsia support. http://anglebug.com/42261836
31*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_PLATFORM_FUCHSIA)
32*8975f5c5SAndroid Build Coastguard Worker std::string executablePath = GetExecutablePath();
33*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE("", executablePath);
34*8975f5c5SAndroid Build Coastguard Worker #endif
35*8975f5c5SAndroid Build Coastguard Worker }
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker // Test getting the executable directory
TEST(SystemUtils,ExecutableDir)38*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ExecutableDir)
39*8975f5c5SAndroid Build Coastguard Worker {
40*8975f5c5SAndroid Build Coastguard Worker // TODO: fuchsia support. http://anglebug.com/42261836
41*8975f5c5SAndroid Build Coastguard Worker #if !defined(ANGLE_PLATFORM_FUCHSIA)
42*8975f5c5SAndroid Build Coastguard Worker std::string executableDir = GetExecutableDirectory();
43*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE("", executableDir);
44*8975f5c5SAndroid Build Coastguard Worker
45*8975f5c5SAndroid Build Coastguard Worker std::string executablePath = GetExecutablePath();
46*8975f5c5SAndroid Build Coastguard Worker EXPECT_LT(executableDir.size(), executablePath.size());
47*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(0, strncmp(executableDir.c_str(), executablePath.c_str(), executableDir.size()));
48*8975f5c5SAndroid Build Coastguard Worker #endif
49*8975f5c5SAndroid Build Coastguard Worker }
50*8975f5c5SAndroid Build Coastguard Worker
51*8975f5c5SAndroid Build Coastguard Worker // Test setting environment variables
TEST(SystemUtils,Environment)52*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, Environment)
53*8975f5c5SAndroid Build Coastguard Worker {
54*8975f5c5SAndroid Build Coastguard Worker constexpr char kEnvVarName[] = "UNITTEST_ENV_VARIABLE";
55*8975f5c5SAndroid Build Coastguard Worker constexpr char kEnvVarValue[] = "The quick brown fox jumps over the lazy dog";
56*8975f5c5SAndroid Build Coastguard Worker
57*8975f5c5SAndroid Build Coastguard Worker bool setEnvDone = SetEnvironmentVar(kEnvVarName, kEnvVarValue);
58*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(setEnvDone);
59*8975f5c5SAndroid Build Coastguard Worker
60*8975f5c5SAndroid Build Coastguard Worker std::string readback = GetEnvironmentVar(kEnvVarName);
61*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(kEnvVarValue, readback);
62*8975f5c5SAndroid Build Coastguard Worker
63*8975f5c5SAndroid Build Coastguard Worker bool unsetEnvDone = UnsetEnvironmentVar(kEnvVarName);
64*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(unsetEnvDone);
65*8975f5c5SAndroid Build Coastguard Worker
66*8975f5c5SAndroid Build Coastguard Worker readback = GetEnvironmentVar(kEnvVarName);
67*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ("", readback);
68*8975f5c5SAndroid Build Coastguard Worker }
69*8975f5c5SAndroid Build Coastguard Worker
70*8975f5c5SAndroid Build Coastguard Worker // Test CPU time measurement with a small operation
71*8975f5c5SAndroid Build Coastguard Worker // (pretty much the measurement itself)
TEST(SystemUtils,CpuTimeSmallOp)72*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, CpuTimeSmallOp)
73*8975f5c5SAndroid Build Coastguard Worker {
74*8975f5c5SAndroid Build Coastguard Worker double cpuTimeStart = GetCurrentProcessCpuTime();
75*8975f5c5SAndroid Build Coastguard Worker double cpuTimeEnd = GetCurrentProcessCpuTime();
76*8975f5c5SAndroid Build Coastguard Worker EXPECT_GE(cpuTimeEnd, cpuTimeStart);
77*8975f5c5SAndroid Build Coastguard Worker }
78*8975f5c5SAndroid Build Coastguard Worker
79*8975f5c5SAndroid Build Coastguard Worker // Test CPU time measurement with a sleepy operation
TEST(SystemUtils,CpuTimeSleepy)80*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, CpuTimeSleepy)
81*8975f5c5SAndroid Build Coastguard Worker {
82*8975f5c5SAndroid Build Coastguard Worker double cpuTimeStart = GetCurrentProcessCpuTime();
83*8975f5c5SAndroid Build Coastguard Worker angle::Sleep(1);
84*8975f5c5SAndroid Build Coastguard Worker double cpuTimeEnd = GetCurrentProcessCpuTime();
85*8975f5c5SAndroid Build Coastguard Worker EXPECT_GE(cpuTimeEnd, cpuTimeStart);
86*8975f5c5SAndroid Build Coastguard Worker }
87*8975f5c5SAndroid Build Coastguard Worker
88*8975f5c5SAndroid Build Coastguard Worker // Test CPU time measurement with a heavy operation
TEST(SystemUtils,CpuTimeHeavyOp)89*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, CpuTimeHeavyOp)
90*8975f5c5SAndroid Build Coastguard Worker {
91*8975f5c5SAndroid Build Coastguard Worker constexpr size_t bufferSize = 1048576;
92*8975f5c5SAndroid Build Coastguard Worker std::vector<uint8_t> buffer(bufferSize, 1);
93*8975f5c5SAndroid Build Coastguard Worker double cpuTimeStart = GetCurrentProcessCpuTime();
94*8975f5c5SAndroid Build Coastguard Worker memset(buffer.data(), 0, bufferSize);
95*8975f5c5SAndroid Build Coastguard Worker double cpuTimeEnd = GetCurrentProcessCpuTime();
96*8975f5c5SAndroid Build Coastguard Worker EXPECT_GE(cpuTimeEnd, cpuTimeStart);
97*8975f5c5SAndroid Build Coastguard Worker }
98*8975f5c5SAndroid Build Coastguard Worker
99*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_POSIX)
TEST(SystemUtils,ConcatenatePathSimple)100*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePathSimple)
101*8975f5c5SAndroid Build Coastguard Worker {
102*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "/this/is/path1";
103*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this/is/path2";
104*8975f5c5SAndroid Build Coastguard Worker std::string expected = "/this/is/path1/this/is/path2";
105*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
106*8975f5c5SAndroid Build Coastguard Worker }
107*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePath1Empty)108*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePath1Empty)
109*8975f5c5SAndroid Build Coastguard Worker {
110*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "";
111*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this/is/path2";
112*8975f5c5SAndroid Build Coastguard Worker std::string expected = "this/is/path2";
113*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
114*8975f5c5SAndroid Build Coastguard Worker }
115*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePath2Empty)116*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePath2Empty)
117*8975f5c5SAndroid Build Coastguard Worker {
118*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "/this/is/path1";
119*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "";
120*8975f5c5SAndroid Build Coastguard Worker std::string expected = "/this/is/path1";
121*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
122*8975f5c5SAndroid Build Coastguard Worker }
123*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePath2FullPath)124*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePath2FullPath)
125*8975f5c5SAndroid Build Coastguard Worker {
126*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "/this/is/path1";
127*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "/this/is/path2";
128*8975f5c5SAndroid Build Coastguard Worker std::string expected = "/this/is/path2";
129*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
130*8975f5c5SAndroid Build Coastguard Worker }
131*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePathRedundantSeparators)132*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePathRedundantSeparators)
133*8975f5c5SAndroid Build Coastguard Worker {
134*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "/this/is/path1/";
135*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this/is/path2";
136*8975f5c5SAndroid Build Coastguard Worker std::string expected = "/this/is/path1/this/is/path2";
137*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
138*8975f5c5SAndroid Build Coastguard Worker }
139*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,IsFullPath)140*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, IsFullPath)
141*8975f5c5SAndroid Build Coastguard Worker {
142*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "/this/is/path1/";
143*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this/is/path2";
144*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(IsFullPath(path1));
145*8975f5c5SAndroid Build Coastguard Worker EXPECT_FALSE(IsFullPath(path2));
146*8975f5c5SAndroid Build Coastguard Worker }
147*8975f5c5SAndroid Build Coastguard Worker #elif defined(ANGLE_PLATFORM_WINDOWS)
TEST(SystemUtils,ConcatenatePathSimple)148*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePathSimple)
149*8975f5c5SAndroid Build Coastguard Worker {
150*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "C:\\this\\is\\path1";
151*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this\\is\\path2";
152*8975f5c5SAndroid Build Coastguard Worker std::string expected = "C:\\this\\is\\path1\\this\\is\\path2";
153*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
154*8975f5c5SAndroid Build Coastguard Worker }
155*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePath1Empty)156*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePath1Empty)
157*8975f5c5SAndroid Build Coastguard Worker {
158*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "";
159*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this\\is\\path2";
160*8975f5c5SAndroid Build Coastguard Worker std::string expected = "this\\is\\path2";
161*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
162*8975f5c5SAndroid Build Coastguard Worker }
163*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePath2Empty)164*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePath2Empty)
165*8975f5c5SAndroid Build Coastguard Worker {
166*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "C:\\this\\is\\path1";
167*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "";
168*8975f5c5SAndroid Build Coastguard Worker std::string expected = "C:\\this\\is\\path1";
169*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
170*8975f5c5SAndroid Build Coastguard Worker }
171*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePath2FullPath)172*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePath2FullPath)
173*8975f5c5SAndroid Build Coastguard Worker {
174*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "C:\\this\\is\\path1";
175*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "C:\\this\\is\\path2";
176*8975f5c5SAndroid Build Coastguard Worker std::string expected = "C:\\this\\is\\path2";
177*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
178*8975f5c5SAndroid Build Coastguard Worker }
179*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePathRedundantSeparators)180*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePathRedundantSeparators)
181*8975f5c5SAndroid Build Coastguard Worker {
182*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "C:\\this\\is\\path1\\";
183*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this\\is\\path2";
184*8975f5c5SAndroid Build Coastguard Worker std::string expected = "C:\\this\\is\\path1\\this\\is\\path2";
185*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
186*8975f5c5SAndroid Build Coastguard Worker }
187*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePathRedundantSeparators2)188*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePathRedundantSeparators2)
189*8975f5c5SAndroid Build Coastguard Worker {
190*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "C:\\this\\is\\path1\\";
191*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "\\this\\is\\path2";
192*8975f5c5SAndroid Build Coastguard Worker std::string expected = "C:\\this\\is\\path1\\this\\is\\path2";
193*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
194*8975f5c5SAndroid Build Coastguard Worker }
195*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,ConcatenatePathRedundantSeparators3)196*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, ConcatenatePathRedundantSeparators3)
197*8975f5c5SAndroid Build Coastguard Worker {
198*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "C:\\this\\is\\path1";
199*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "\\this\\is\\path2";
200*8975f5c5SAndroid Build Coastguard Worker std::string expected = "C:\\this\\is\\path1\\this\\is\\path2";
201*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(ConcatenatePath(path1, path2), expected);
202*8975f5c5SAndroid Build Coastguard Worker }
203*8975f5c5SAndroid Build Coastguard Worker
TEST(SystemUtils,IsFullPath)204*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, IsFullPath)
205*8975f5c5SAndroid Build Coastguard Worker {
206*8975f5c5SAndroid Build Coastguard Worker std::string path1 = "C:\\this\\is\\path1\\";
207*8975f5c5SAndroid Build Coastguard Worker std::string path2 = "this\\is\\path2";
208*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(IsFullPath(path1));
209*8975f5c5SAndroid Build Coastguard Worker EXPECT_FALSE(IsFullPath(path2));
210*8975f5c5SAndroid Build Coastguard Worker }
211*8975f5c5SAndroid Build Coastguard Worker #endif
212*8975f5c5SAndroid Build Coastguard Worker
213*8975f5c5SAndroid Build Coastguard Worker // Temporary file creation is not supported on Android right now.
214*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_ANDROID)
215*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_CreateAndDeleteTemporaryFile DISABLED_CreateAndDeleteTemporaryFile
216*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_CreateAndDeleteFileInTempDir DISABLED_CreateAndDeleteFileInTempDir
217*8975f5c5SAndroid Build Coastguard Worker #else
218*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_CreateAndDeleteTemporaryFile CreateAndDeleteTemporaryFile
219*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_CreateAndDeleteFileInTempDir CreateAndDeleteFileInTempDir
220*8975f5c5SAndroid Build Coastguard Worker #endif // defined(ANGLE_PLATFORM_ANDROID)
221*8975f5c5SAndroid Build Coastguard Worker
222*8975f5c5SAndroid Build Coastguard Worker // Test creating/using temporary file
TEST(SystemUtils,MAYBE_CreateAndDeleteTemporaryFile)223*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, MAYBE_CreateAndDeleteTemporaryFile)
224*8975f5c5SAndroid Build Coastguard Worker {
225*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> path = CreateTemporaryFile();
226*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(path.valid());
227*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(!path.value().empty());
228*8975f5c5SAndroid Build Coastguard Worker
229*8975f5c5SAndroid Build Coastguard Worker const std::string testContents = "test output";
230*8975f5c5SAndroid Build Coastguard Worker
231*8975f5c5SAndroid Build Coastguard Worker // Test writing
232*8975f5c5SAndroid Build Coastguard Worker std::ofstream out;
233*8975f5c5SAndroid Build Coastguard Worker out.open(path.value());
234*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(out.is_open());
235*8975f5c5SAndroid Build Coastguard Worker out << testContents;
236*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(out.good());
237*8975f5c5SAndroid Build Coastguard Worker out.close();
238*8975f5c5SAndroid Build Coastguard Worker
239*8975f5c5SAndroid Build Coastguard Worker // Test reading
240*8975f5c5SAndroid Build Coastguard Worker std::ifstream in;
241*8975f5c5SAndroid Build Coastguard Worker in.open(path.value());
242*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(in.is_open());
243*8975f5c5SAndroid Build Coastguard Worker std::ostringstream sstr;
244*8975f5c5SAndroid Build Coastguard Worker sstr << in.rdbuf();
245*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(sstr.str(), testContents);
246*8975f5c5SAndroid Build Coastguard Worker in.close();
247*8975f5c5SAndroid Build Coastguard Worker
248*8975f5c5SAndroid Build Coastguard Worker // Test deleting
249*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(DeleteSystemFile(path.value().c_str()));
250*8975f5c5SAndroid Build Coastguard Worker }
251*8975f5c5SAndroid Build Coastguard Worker
252*8975f5c5SAndroid Build Coastguard Worker // Test creating/using file created in system's temporary directory
TEST(SystemUtils,MAYBE_CreateAndDeleteFileInTempDir)253*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, MAYBE_CreateAndDeleteFileInTempDir)
254*8975f5c5SAndroid Build Coastguard Worker {
255*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> tempDir = GetTempDirectory();
256*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(tempDir.valid());
257*8975f5c5SAndroid Build Coastguard Worker
258*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> path = CreateTemporaryFileInDirectory(tempDir.value());
259*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(path.valid());
260*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(!path.value().empty());
261*8975f5c5SAndroid Build Coastguard Worker
262*8975f5c5SAndroid Build Coastguard Worker const std::string testContents = "test output";
263*8975f5c5SAndroid Build Coastguard Worker
264*8975f5c5SAndroid Build Coastguard Worker // Test writing
265*8975f5c5SAndroid Build Coastguard Worker std::ofstream out;
266*8975f5c5SAndroid Build Coastguard Worker out.open(path.value());
267*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(out.is_open());
268*8975f5c5SAndroid Build Coastguard Worker out << "test output";
269*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(out.good());
270*8975f5c5SAndroid Build Coastguard Worker out.close();
271*8975f5c5SAndroid Build Coastguard Worker
272*8975f5c5SAndroid Build Coastguard Worker // Test reading
273*8975f5c5SAndroid Build Coastguard Worker std::ifstream in;
274*8975f5c5SAndroid Build Coastguard Worker in.open(path.value());
275*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(in.is_open());
276*8975f5c5SAndroid Build Coastguard Worker std::ostringstream sstr;
277*8975f5c5SAndroid Build Coastguard Worker sstr << in.rdbuf();
278*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(sstr.str(), testContents);
279*8975f5c5SAndroid Build Coastguard Worker in.close();
280*8975f5c5SAndroid Build Coastguard Worker
281*8975f5c5SAndroid Build Coastguard Worker // Test deleting
282*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(DeleteSystemFile(path.value().c_str()));
283*8975f5c5SAndroid Build Coastguard Worker }
284*8975f5c5SAndroid Build Coastguard Worker
285*8975f5c5SAndroid Build Coastguard Worker // Test retrieving page size
TEST(SystemUtils,PageSize)286*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, PageSize)
287*8975f5c5SAndroid Build Coastguard Worker {
288*8975f5c5SAndroid Build Coastguard Worker size_t pageSize = GetPageSize();
289*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(pageSize > 0);
290*8975f5c5SAndroid Build Coastguard Worker }
291*8975f5c5SAndroid Build Coastguard Worker
292*8975f5c5SAndroid Build Coastguard Worker // mprotect is not supported on Fuchsia right now.
293*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_FUCHSIA)
294*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerInit DISABLED_PageFaultHandlerInit
295*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerProtect DISABLED_PageFaultHandlerProtect
296*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerDefaultHandler DISABLED_PageFaultHandlerDefaultHandler
297*8975f5c5SAndroid Build Coastguard Worker // mprotect tests hang on macOS M1. Also applies to the iOS simulator.
298*8975f5c5SAndroid Build Coastguard Worker #elif ANGLE_PLATFORM_MACOS || ANGLE_PLATFORM_IOS_FAMILY_SIMULATOR
299*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerInit PageFaultHandlerInit
300*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerProtect DISABLED_PageFaultHandlerProtect
301*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerDefaultHandler DISABLED_PageFaultHandlerDefaultHandler
302*8975f5c5SAndroid Build Coastguard Worker #else
303*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerInit PageFaultHandlerInit
304*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerProtect PageFaultHandlerProtect
305*8975f5c5SAndroid Build Coastguard Worker # define MAYBE_PageFaultHandlerDefaultHandler PageFaultHandlerDefaultHandler
306*8975f5c5SAndroid Build Coastguard Worker #endif // defined(ANGLE_PLATFORM_FUCHSIA)
307*8975f5c5SAndroid Build Coastguard Worker
308*8975f5c5SAndroid Build Coastguard Worker // Test initializing and cleaning up page fault handler.
TEST(SystemUtils,MAYBE_PageFaultHandlerInit)309*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, MAYBE_PageFaultHandlerInit)
310*8975f5c5SAndroid Build Coastguard Worker {
311*8975f5c5SAndroid Build Coastguard Worker PageFaultCallback callback = [](uintptr_t address) {
312*8975f5c5SAndroid Build Coastguard Worker return PageFaultHandlerRangeType::InRange;
313*8975f5c5SAndroid Build Coastguard Worker };
314*8975f5c5SAndroid Build Coastguard Worker
315*8975f5c5SAndroid Build Coastguard Worker std::unique_ptr<PageFaultHandler> handler(CreatePageFaultHandler(callback));
316*8975f5c5SAndroid Build Coastguard Worker
317*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(handler->enable());
318*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(handler->disable());
319*8975f5c5SAndroid Build Coastguard Worker }
320*8975f5c5SAndroid Build Coastguard Worker
321*8975f5c5SAndroid Build Coastguard Worker // Test write protecting and unprotecting memory
TEST(SystemUtils,MAYBE_PageFaultHandlerProtect)322*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, MAYBE_PageFaultHandlerProtect)
323*8975f5c5SAndroid Build Coastguard Worker {
324*8975f5c5SAndroid Build Coastguard Worker size_t pageSize = GetPageSize();
325*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(pageSize > 0);
326*8975f5c5SAndroid Build Coastguard Worker
327*8975f5c5SAndroid Build Coastguard Worker std::vector<float> data = std::vector<float>(100);
328*8975f5c5SAndroid Build Coastguard Worker size_t dataSize = sizeof(float) * data.size();
329*8975f5c5SAndroid Build Coastguard Worker uintptr_t dataStart = reinterpret_cast<uintptr_t>(data.data());
330*8975f5c5SAndroid Build Coastguard Worker uintptr_t protectionStart = rx::roundDownPow2(dataStart, pageSize);
331*8975f5c5SAndroid Build Coastguard Worker uintptr_t protectionEnd = rx::roundUpPow2(dataStart + dataSize, pageSize);
332*8975f5c5SAndroid Build Coastguard Worker
333*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
334*8975f5c5SAndroid Build Coastguard Worker bool handlerCalled = false;
335*8975f5c5SAndroid Build Coastguard Worker
336*8975f5c5SAndroid Build Coastguard Worker PageFaultCallback callback = [&mutex, pageSize, dataStart, dataSize,
337*8975f5c5SAndroid Build Coastguard Worker &handlerCalled](uintptr_t address) {
338*8975f5c5SAndroid Build Coastguard Worker if (address >= dataStart && address < dataStart + dataSize)
339*8975f5c5SAndroid Build Coastguard Worker {
340*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mutex);
341*8975f5c5SAndroid Build Coastguard Worker uintptr_t pageStart = rx::roundDownPow2(address, pageSize);
342*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(UnprotectMemory(pageStart, pageSize));
343*8975f5c5SAndroid Build Coastguard Worker handlerCalled = true;
344*8975f5c5SAndroid Build Coastguard Worker return PageFaultHandlerRangeType::InRange;
345*8975f5c5SAndroid Build Coastguard Worker }
346*8975f5c5SAndroid Build Coastguard Worker else
347*8975f5c5SAndroid Build Coastguard Worker {
348*8975f5c5SAndroid Build Coastguard Worker return PageFaultHandlerRangeType::OutOfRange;
349*8975f5c5SAndroid Build Coastguard Worker }
350*8975f5c5SAndroid Build Coastguard Worker };
351*8975f5c5SAndroid Build Coastguard Worker
352*8975f5c5SAndroid Build Coastguard Worker std::unique_ptr<PageFaultHandler> handler(CreatePageFaultHandler(callback));
353*8975f5c5SAndroid Build Coastguard Worker handler->enable();
354*8975f5c5SAndroid Build Coastguard Worker
355*8975f5c5SAndroid Build Coastguard Worker size_t protectionSize = protectionEnd - protectionStart;
356*8975f5c5SAndroid Build Coastguard Worker
357*8975f5c5SAndroid Build Coastguard Worker // Test Protect
358*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(ProtectMemory(protectionStart, protectionSize));
359*8975f5c5SAndroid Build Coastguard Worker
360*8975f5c5SAndroid Build Coastguard Worker data[0] = 0.0;
361*8975f5c5SAndroid Build Coastguard Worker
362*8975f5c5SAndroid Build Coastguard Worker {
363*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mutex);
364*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(handlerCalled);
365*8975f5c5SAndroid Build Coastguard Worker }
366*8975f5c5SAndroid Build Coastguard Worker
367*8975f5c5SAndroid Build Coastguard Worker // Test Protect and unprotect
368*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(ProtectMemory(protectionStart, protectionSize));
369*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(UnprotectMemory(protectionStart, protectionSize));
370*8975f5c5SAndroid Build Coastguard Worker
371*8975f5c5SAndroid Build Coastguard Worker handlerCalled = false;
372*8975f5c5SAndroid Build Coastguard Worker data[0] = 0.0;
373*8975f5c5SAndroid Build Coastguard Worker EXPECT_FALSE(handlerCalled);
374*8975f5c5SAndroid Build Coastguard Worker
375*8975f5c5SAndroid Build Coastguard Worker // Clean up
376*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(handler->disable());
377*8975f5c5SAndroid Build Coastguard Worker }
378*8975f5c5SAndroid Build Coastguard Worker
379*8975f5c5SAndroid Build Coastguard Worker // Tests basic usage of StripFilenameFromPath.
TEST(SystemUtils,StripFilenameFromPathUsage)380*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, StripFilenameFromPathUsage)
381*8975f5c5SAndroid Build Coastguard Worker {
382*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(StripFilenameFromPath("/path/to/tests/angle_tests"), "/path/to/tests");
383*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(StripFilenameFromPath("C:\\tests\\angle_tests.exe"), "C:\\tests");
384*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(StripFilenameFromPath("angle_tests"), "");
385*8975f5c5SAndroid Build Coastguard Worker }
386*8975f5c5SAndroid Build Coastguard Worker
387*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_POSIX)
388*8975f5c5SAndroid Build Coastguard Worker std::mutex gCustomHandlerMutex;
389*8975f5c5SAndroid Build Coastguard Worker bool gCustomHandlerCalled = false;
390*8975f5c5SAndroid Build Coastguard Worker
CustomSegfaultHandlerFunction(int sig,siginfo_t * info,void * unused)391*8975f5c5SAndroid Build Coastguard Worker void CustomSegfaultHandlerFunction(int sig, siginfo_t *info, void *unused)
392*8975f5c5SAndroid Build Coastguard Worker {
393*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(gCustomHandlerMutex);
394*8975f5c5SAndroid Build Coastguard Worker gCustomHandlerCalled = true;
395*8975f5c5SAndroid Build Coastguard Worker }
396*8975f5c5SAndroid Build Coastguard Worker
397*8975f5c5SAndroid Build Coastguard Worker // Test if the default page fault handler is called on OutOfRange.
TEST(SystemUtils,MAYBE_PageFaultHandlerDefaultHandler)398*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, MAYBE_PageFaultHandlerDefaultHandler)
399*8975f5c5SAndroid Build Coastguard Worker {
400*8975f5c5SAndroid Build Coastguard Worker size_t pageSize = GetPageSize();
401*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(pageSize > 0);
402*8975f5c5SAndroid Build Coastguard Worker
403*8975f5c5SAndroid Build Coastguard Worker std::vector<float> data = std::vector<float>(100);
404*8975f5c5SAndroid Build Coastguard Worker size_t dataSize = sizeof(float) * data.size();
405*8975f5c5SAndroid Build Coastguard Worker uintptr_t dataStart = reinterpret_cast<uintptr_t>(data.data());
406*8975f5c5SAndroid Build Coastguard Worker uintptr_t protectionStart = rx::roundDownPow2(dataStart, pageSize);
407*8975f5c5SAndroid Build Coastguard Worker uintptr_t protectionEnd = rx::roundUpPow2(dataStart + dataSize, pageSize);
408*8975f5c5SAndroid Build Coastguard Worker size_t protectionSize = protectionEnd - protectionStart;
409*8975f5c5SAndroid Build Coastguard Worker
410*8975f5c5SAndroid Build Coastguard Worker // Create custom handler
411*8975f5c5SAndroid Build Coastguard Worker struct sigaction sigAction = {};
412*8975f5c5SAndroid Build Coastguard Worker sigAction.sa_flags = SA_SIGINFO;
413*8975f5c5SAndroid Build Coastguard Worker sigAction.sa_sigaction = &CustomSegfaultHandlerFunction;
414*8975f5c5SAndroid Build Coastguard Worker sigemptyset(&sigAction.sa_mask);
415*8975f5c5SAndroid Build Coastguard Worker
416*8975f5c5SAndroid Build Coastguard Worker struct sigaction oldSigSegv = {};
417*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(sigaction(SIGSEGV, &sigAction, &oldSigSegv) == 0);
418*8975f5c5SAndroid Build Coastguard Worker struct sigaction oldSigBus = {};
419*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(sigaction(SIGBUS, &sigAction, &oldSigBus) == 0);
420*8975f5c5SAndroid Build Coastguard Worker
421*8975f5c5SAndroid Build Coastguard Worker PageFaultCallback callback = [protectionStart, protectionSize](uintptr_t address) {
422*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(UnprotectMemory(protectionStart, protectionSize));
423*8975f5c5SAndroid Build Coastguard Worker return PageFaultHandlerRangeType::OutOfRange;
424*8975f5c5SAndroid Build Coastguard Worker };
425*8975f5c5SAndroid Build Coastguard Worker
426*8975f5c5SAndroid Build Coastguard Worker std::unique_ptr<PageFaultHandler> handler(CreatePageFaultHandler(callback));
427*8975f5c5SAndroid Build Coastguard Worker handler->enable();
428*8975f5c5SAndroid Build Coastguard Worker
429*8975f5c5SAndroid Build Coastguard Worker // Test Protect
430*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(ProtectMemory(protectionStart, protectionSize));
431*8975f5c5SAndroid Build Coastguard Worker
432*8975f5c5SAndroid Build Coastguard Worker data[0] = 0.0;
433*8975f5c5SAndroid Build Coastguard Worker
434*8975f5c5SAndroid Build Coastguard Worker {
435*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(gCustomHandlerMutex);
436*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(gCustomHandlerCalled);
437*8975f5c5SAndroid Build Coastguard Worker }
438*8975f5c5SAndroid Build Coastguard Worker
439*8975f5c5SAndroid Build Coastguard Worker // Clean up
440*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(handler->disable());
441*8975f5c5SAndroid Build Coastguard Worker
442*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(sigaction(SIGSEGV, &oldSigSegv, nullptr) == 0);
443*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(sigaction(SIGBUS, &oldSigBus, nullptr) == 0);
444*8975f5c5SAndroid Build Coastguard Worker }
445*8975f5c5SAndroid Build Coastguard Worker #else
TEST(SystemUtils,MAYBE_PageFaultHandlerDefaultHandler)446*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, MAYBE_PageFaultHandlerDefaultHandler) {}
447*8975f5c5SAndroid Build Coastguard Worker #endif
448*8975f5c5SAndroid Build Coastguard Worker
449*8975f5c5SAndroid Build Coastguard Worker // Tests basic usage of GetCurrentThreadId.
TEST(SystemUtils,GetCurrentThreadId)450*8975f5c5SAndroid Build Coastguard Worker TEST(SystemUtils, GetCurrentThreadId)
451*8975f5c5SAndroid Build Coastguard Worker {
452*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kThreadCount = 64;
453*8975f5c5SAndroid Build Coastguard Worker
454*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
455*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
456*8975f5c5SAndroid Build Coastguard Worker
457*8975f5c5SAndroid Build Coastguard Worker std::vector<std::thread> threads;
458*8975f5c5SAndroid Build Coastguard Worker std::set<ThreadId> threadIds;
459*8975f5c5SAndroid Build Coastguard Worker size_t readyCount = 0;
460*8975f5c5SAndroid Build Coastguard Worker
461*8975f5c5SAndroid Build Coastguard Worker for (size_t i = 0; i < kThreadCount; ++i)
462*8975f5c5SAndroid Build Coastguard Worker {
463*8975f5c5SAndroid Build Coastguard Worker threads.emplace_back([&]() {
464*8975f5c5SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(mutex);
465*8975f5c5SAndroid Build Coastguard Worker
466*8975f5c5SAndroid Build Coastguard Worker // Get threadId
467*8975f5c5SAndroid Build Coastguard Worker const angle::ThreadId threadId = angle::GetCurrentThreadId();
468*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE(threadId, angle::InvalidThreadId());
469*8975f5c5SAndroid Build Coastguard Worker threadIds.insert(threadId);
470*8975f5c5SAndroid Build Coastguard Worker
471*8975f5c5SAndroid Build Coastguard Worker // Allow thread to finish only when all threads received the id.
472*8975f5c5SAndroid Build Coastguard Worker // Otherwise new thread may reuse Id of already completed but not joined thread.
473*8975f5c5SAndroid Build Coastguard Worker // Problem can be reproduced on Window platform, for example.
474*8975f5c5SAndroid Build Coastguard Worker ++readyCount;
475*8975f5c5SAndroid Build Coastguard Worker if (readyCount < kThreadCount)
476*8975f5c5SAndroid Build Coastguard Worker {
477*8975f5c5SAndroid Build Coastguard Worker condVar.wait(lock, [&]() { return readyCount == kThreadCount; });
478*8975f5c5SAndroid Build Coastguard Worker }
479*8975f5c5SAndroid Build Coastguard Worker else
480*8975f5c5SAndroid Build Coastguard Worker {
481*8975f5c5SAndroid Build Coastguard Worker condVar.notify_all();
482*8975f5c5SAndroid Build Coastguard Worker }
483*8975f5c5SAndroid Build Coastguard Worker
484*8975f5c5SAndroid Build Coastguard Worker // Check that threadId is still the same.
485*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(threadId, angle::GetCurrentThreadId());
486*8975f5c5SAndroid Build Coastguard Worker });
487*8975f5c5SAndroid Build Coastguard Worker }
488*8975f5c5SAndroid Build Coastguard Worker
489*8975f5c5SAndroid Build Coastguard Worker for (size_t i = 0; i < kThreadCount; ++i)
490*8975f5c5SAndroid Build Coastguard Worker {
491*8975f5c5SAndroid Build Coastguard Worker threads[i].join();
492*8975f5c5SAndroid Build Coastguard Worker }
493*8975f5c5SAndroid Build Coastguard Worker
494*8975f5c5SAndroid Build Coastguard Worker // Check that all threadIds were unique.
495*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(threadIds.size(), kThreadCount);
496*8975f5c5SAndroid Build Coastguard Worker }
497*8975f5c5SAndroid Build Coastguard Worker
498*8975f5c5SAndroid Build Coastguard Worker } // anonymous namespace
499