Repository navigation
Expand file tree
/
Copy pathLibJSCToolsTestUtilities.h
More file actions
184 lines (151 loc) · 6.33 KB
/
Copy pathLibJSCToolsTestUtilities.h
File metadata and controls
184 lines (151 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* Copyright (C) 2026 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR)
#include <mach/mach.h>
#include <memory>
#include <span>
#include <stdint.h>
#include <string_view>
#include <wtf/DataLog.h>
#include <wtf/HexNumber.h>
#include <wtf/MonotonicTime.h>
#include <wtf/RefPtr.h>
#include <wtf/Seconds.h>
#include <wtf/Vector.h>
namespace JSC {
namespace Corpse {
class Process;
class Snapshot;
}
}
namespace JSCToolsTest {
// Assertions report against these, and main reports the totals.
extern unsigned assertionsRun;
extern unsigned assertionsFailed;
extern unsigned suitesSkipped;
// Only suites whose name contains this substring run. Null runs all of them.
extern const char* suiteFilter;
extern bool verbose;
void skipSuite(const char* name, const char* why);
// Announces a suite, times it, and reports on the way out. Destroyed on every path out
// of a suite, including the early returns a suite takes when it cannot set itself up.
class SuiteTracer {
public:
explicit SuiteTracer(const char* name);
~SuiteTracer();
SuiteTracer(const SuiteTracer&) = delete;
SuiteTracer& operator=(const SuiteTracer&) = delete;
SuiteTracer(SuiteTracer&&) = delete;
SuiteTracer& operator=(SuiteTracer&&) = delete;
bool shouldRun() const { return m_shouldRun; }
private:
const char* m_name;
MonotonicTime m_start;
bool m_shouldRun;
};
Seconds totalSuiteTime();
// Nothing is printed for a passing assertion: a passing run should be quiet, and
// a failing one should say only what failed.
#define TEST_ASSERT(condition, message) \
do { \
++JSCToolsTest::assertionsRun; \
if (!(condition)) { \
++JSCToolsTest::assertionsFailed; \
dataLogLn("FAIL: ", message, " (", #condition, ") at ", __FILE__, ":", __LINE__); \
} \
} while (0)
// For values dataLog can print. Reports both sides, which is what makes a
// failure diagnosable without a debugger.
#define TEST_ASSERT_EQ(actual, expected, message) \
do { \
++JSCToolsTest::assertionsRun; \
auto testActual = (actual); \
auto testExpected = (expected); \
if (!(testActual == testExpected)) { \
++JSCToolsTest::assertionsFailed; \
dataLogLn("FAIL: ", message, ": got ", testActual, ", expected ", testExpected, \
" at ", __FILE__, ":", __LINE__); \
} \
} while (0)
#define TEST_ASSERT_HEX_EQ(actual, expected, message) \
do { \
++JSCToolsTest::assertionsRun; \
uint64_t testActual = (actual); \
uint64_t testExpected = (expected); \
if (testActual != testExpected) { \
++JSCToolsTest::assertionsFailed; \
dataLogLn("FAIL: ", message, ": got 0x", hex(testActual), ", expected 0x", hex(testExpected), \
" at ", __FILE__, ":", __LINE__); \
} \
} while (0)
// The number of names in this task's Mach port name space. Used to show that a
// sequence of operations leaves no port behind.
unsigned machPortNameCount();
// The number of send rights this task holds for `port`, or 0 if it holds no name for
// it. A task that acquires a port it already has a name for gets another reference
// under that same name rather than a new name, so a right that is taken and never
// given back shows up here and not in machPortNameCount().
unsigned machPortSendRightCount(mach_port_t);
// Attaches to this process and takes a corpse of it. That is what lets a test
// check what a corpse reports against what this process already knows about
// itself, and it needs no privilege: a task may always snapshot itself.
//
// Reports the failure if either step does not work, so a caller only has to
// check isValid() and return.
class SelfSnapshot {
public:
SelfSnapshot();
~SelfSnapshot();
SelfSnapshot(const SelfSnapshot&) = delete;
SelfSnapshot& operator=(const SelfSnapshot&) = delete;
bool isValid() const;
JSC::Corpse::Snapshot& snapshot() const;
RefPtr<JSC::Corpse::Process> process() const;
private:
RefPtr<JSC::Corpse::Process> m_process;
std::unique_ptr<JSC::Corpse::Snapshot> m_snapshot;
};
// Threads that park themselves until stopped, each under a name of our choosing,
// so that a corpse of this process contains threads whose properties are known.
class ParkedThreads {
public:
struct Thread;
// pthread keeps a thread name in a fixed buffer, so a longer name arrives cut
// to this length.
static constexpr size_t maximumNameLength = 63;
~ParkedThreads();
// Returns false if the thread could not be created.
bool spawn(const char* name);
// Blocks until every spawned thread is parked, so that a snapshot taken
// afterwards sees them with their names set and their stacks in use.
bool waitUntilAllParked();
void stopAndJoin();
size_t count() const { return m_threads.size(); }
private:
Vector<Thread*> m_threads;
};
} // namespace JSCToolsTest
#endif // (OS(MACOS) || USE(APPLE_INTERNAL_SDK)) && !PLATFORM(MACCATALYST) && !PLATFORM(IOS_FAMILY_SIMULATOR)