this repo has no description
1/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */
2#pragma once
3
4#include <functional>
5#include <string>
6
7#include "gtest/gtest.h"
8
9#include "handles.h"
10#include "objects.h"
11#include "runtime.h"
12
13// Define EXPECT_DEBUG_ONLY_DEATH, which is like gtest's
14// EXPECT_DEBUG_DEATH, except that it does not execute the given statment
15// at all in release mode. This is necessary because most of our tests
16// which rely on EXPECT_DEBUG_DEATH will cause unsafe operations to
17// occur if the statement is executed.
18
19#ifdef NDEBUG
20
21#define EXPECT_DEBUG_ONLY_DEATH(stmt, pattern)
22
23#else
24
25#define EXPECT_DEBUG_ONLY_DEATH(stmt, pattern) \
26 EXPECT_DEBUG_DEATH((stmt), (pattern))
27
28#endif
29
30namespace py {
31
32namespace testing {
33
34Runtime* createTestRuntime();
35
36bool useCppInterpreter();
37
38class RuntimeFixture : public ::testing::Test {
39 protected:
40 void SetUp() override {
41 runtime_ = createTestRuntime();
42 thread_ = runtime_->mainThread();
43 }
44
45 void TearDown() override { delete runtime_; }
46
47 Runtime* runtime_;
48 Thread* thread_;
49};
50
51// Basic variant wrapper for a subset of Python values, used by
52// EXPECT_PYLIST_EQ().
53class Value {
54 public:
55 enum class Type {
56 None,
57 Bool,
58 Int,
59 Float,
60 Str,
61 };
62
63 Value(bool b) : bool_{b}, type_{Type::Bool} {}
64 Value(int i) : Value{static_cast<word>(i)} {}
65 Value(word i) : int_{i}, type_{Type::Int} {}
66 Value(double f) : float_{f}, type_{Type::Float} {}
67 Value(const char* s) : str_{s}, type_{Type::Str} {}
68
69 static Value none();
70
71 Type type() const;
72
73 bool boolVal() const;
74 word intVal() const;
75 double floatVal() const;
76 const char* strVal() const;
77
78 private:
79 union {
80 bool bool_;
81 word int_;
82 double float_;
83 const char* str_;
84 };
85
86 Value() : type_{Type::None} {}
87
88 Type type_;
89};
90
91inline Value Value::none() { return Value{}; }
92
93inline RawObject valueCellValue(RawObject value_cell_obj) {
94 DCHECK(value_cell_obj.isValueCell(), "expected valuecell");
95 return ValueCell::cast(value_cell_obj).value();
96}
97
98// Check if the given Object is a list containing the expected elements.
99::testing::AssertionResult AssertPyListEqual(
100 const char* actual_expr, const char* expected_expr, const Object& actual,
101 const std::vector<Value>& expected);
102
103// The preprocessor doesn't understand grouping by {}, so EXPECT_PYLIST_EQ uses
104// this to support a nice-looking callsite.
105inline std::vector<Value> make_list(std::vector<Value> l) { return l; }
106
107// Used to verify the type, length, and contents of a list. Supports None, bool,
108// int, float, and str values:
109//
110// Handle<Object> list(&scope, moduleAt(...));
111// EXPECT_PYLIST_EQ(*list, {Value::None(), false, 42, 123.456, "a string"});
112#define EXPECT_PYLIST_EQ(l1, ...) \
113 EXPECT_PRED_FORMAT2(::py::testing::AssertPyListEqual, l1, \
114 ::py::testing::make_list(__VA_ARGS__))
115
116// Calls func using the supplied arguments.
117//
118// This opens a new frame linked to the initial frame of the current thread,
119// pushes all the arguments onto the stack, and invokes the interpreter.
120//
121// The caller is responsible for cleaning up any exception state.
122RawObject callFunction(const Function& func, const Tuple& args);
123
124bool tupleContains(const Tuple& object_array, const Object& key);
125
126bool listContains(const Object& list_obj, const Object& key);
127
128// Get the module instance bount to name "__main__".
129// Return Error::object() if not found.
130RawObject findMainModule(Runtime* runtime);
131
132// Get the value bound to name in the main module.
133// Returns Error::object() if not found.
134RawObject mainModuleAt(Runtime* runtime, const char* name);
135
136// Get the value bound to name in the module under the supplied name.
137// Returns Error::object() if not found.
138RawObject moduleAtByCStr(Runtime* runtime, const char* module_name,
139 const char* name);
140
141// Get the name of the type of the given object.
142std::string typeName(Runtime* runtime, RawObject obj);
143
144RawObject typeValueCellAt(RawType type, RawObject name);
145
146struct Locals {
147 word varcount = 0;
148 word argcount = 0;
149 word kwonlyargcount = 0;
150 word posonlyargcount = 0;
151 bool varargs = false;
152 bool varkeyargs = false;
153};
154
155RawCode newCodeWithBytes(View<byte> bytes);
156RawCode newCodeWithBytesConsts(View<byte> bytes, const Tuple& consts);
157RawCode newCodeWithBytesConstsNames(View<byte> bytes, const Tuple& consts,
158 const Tuple& names);
159RawCode newCodeWithBytesConstsNamesFlags(View<byte> bytes, const Tuple& consts,
160 const Tuple& names, word flags);
161RawCode newCodeWithBytesConstsNamesLocals(View<byte> bytes, const Tuple& consts,
162 const Tuple& names, Locals* locals);
163
164RawFunction newEmptyFunction();
165
166RawBytes newBytesFromCStr(Thread* thread, const char* str);
167
168RawBytearray newBytearrayFromCStr(Thread* thread, const char* str);
169
170// Helper for creating weakrefs with the callback as a BoundMethod.
171RawObject newWeakRefWithCallback(Runtime* runtime, Thread* thread,
172 const Object& referent,
173 const Object& callback);
174
175// Helper to allow construction of a RawLargeInt from an initializer list.
176// May construct an invalid LargeInt depending on the digits so we can test
177// normalizeLargeInt().
178RawLargeInt newLargeIntWithDigits(View<uword> digits);
179
180// Creates memoryview objects. This is a convenience helper around
181// Runtime::newMemoryView().
182RawObject newMemoryView(View<byte> bytes, const char* format,
183 ReadOnly read_only = ReadOnly::ReadOnly);
184
185RawTuple newTupleWithNone(word length);
186
187// Helper to create set objects.
188// Equivalent to evaluating "set(range(start, stop))" in Python.
189RawObject setFromRange(word start, word stop);
190
191bool setIncludes(Thread* thread, const SetBase& set, const Object& key);
192
193void setHashAndAdd(Thread* thread, const SetBase& set, const Object& value);
194
195RawObject runBuiltinImpl(BuiltinFunction function,
196 View<std::reference_wrapper<const Object>> args);
197
198RawObject runBuiltin(BuiltinFunction function);
199
200// Create an ad-hoc function with 0 parameters for `code` and execute it in the
201// current thread.
202NODISCARD RawObject runCode(const Code& code);
203
204// Same as `runCode()` but disables bytecode rewriting.
205NODISCARD RawObject runCodeNoBytecodeRewriting(const Code& code);
206
207// Helper to compile and run a snippet of Python code.
208NODISCARD RawObject runFromCStr(Runtime* runtime, const char* c_str);
209
210void addBuiltin(const char* name, BuiltinFunction function,
211 View<const char*> parameter_names, word code_flags);
212
213template <typename... Args>
214RawObject runBuiltin(BuiltinFunction function, const Args&... args) {
215 using ref = std::reference_wrapper<const Object>;
216 ref args_array[] = {ref(args)...};
217 return runBuiltinImpl(function, args_array);
218}
219
220struct FileDeleter {
221 void operator()(char* filename) const {
222 std::remove(filename);
223 delete[] filename;
224 }
225};
226using unique_file_ptr = std::unique_ptr<char, FileDeleter>;
227
228RawObject listFromRange(word start, word stop);
229
230RawObject icLookupAttr(RawMutableTuple caches, word index, LayoutId layout_id);
231
232RawObject icLookupBinaryOp(RawMutableTuple caches, word index,
233 LayoutId left_layout_id, LayoutId right_layout_id,
234 BinaryOpFlags* flags_out);
235
236::testing::AssertionResult containsBytecode(const Function& function,
237 Bytecode bc);
238
239::testing::AssertionResult isBytearrayEqualsBytes(const Object& result,
240 View<byte> expected);
241
242::testing::AssertionResult isBytearrayEqualsCStr(const Object& result,
243 const char* expected);
244
245::testing::AssertionResult isBytesEqualsBytes(const Object& result,
246 View<byte> expected);
247
248::testing::AssertionResult isFloatEqualsDouble(RawObject obj, double expected);
249
250::testing::AssertionResult isMutableBytesEqualsBytes(const Object& result,
251 View<byte> expected);
252
253::testing::AssertionResult isBytesEqualsCStr(const Object& result,
254 const char* expected);
255
256::testing::AssertionResult isStrEquals(const Object& str1, const Object& str2);
257
258::testing::AssertionResult isStrEqualsCStr(RawObject obj, const char* c_str);
259
260::testing::AssertionResult isSymbolIdEquals(SymbolId result, SymbolId expected);
261
262::testing::AssertionResult isIntEqualsWord(RawObject obj, word value);
263
264::testing::AssertionResult isIntEqualsDigits(RawObject obj, View<uword> digits);
265
266RawObject layoutCreateEmpty(Thread* thread);
267
268// Check if the return value of a call and current thread state indicate that an
269// exception was raised with the given type.
270::testing::AssertionResult raised(RawObject return_value, LayoutId layout_id);
271
272// Check if the return value from a call and current thread state indicate that
273// an exception was raised with the given type and message.
274//
275// Since Python exceptions can contain any value, two conventions for finding a
276// string message are supported: directly in thread->pendingExceptionValue()
277// or, if pendingExceptionValue() contains an exception instance, the first
278// element of its args tuple. These situations result from
279// thread->raiseFooError(a_string) in C++ or "raise FooError('a string')" in
280// Python, respectively.
281//
282// message may be nullptr to indicate that the exception value should not be
283// checked.
284::testing::AssertionResult raisedWithStr(RawObject return_value,
285 LayoutId layout_id,
286 const char* message);
287
288void writeFile(const std::string& path, const std::string& contents);
289
290// Simple PointerVisitor that remembers the objects visited.
291class RememberingVisitor : public PointerVisitor {
292 public:
293 virtual void visitPointer(RawObject* pointer, PointerKind) {
294 pointers_.push_back(*pointer);
295 }
296
297 word count() { return pointers_.size(); }
298
299 bool hasVisited(RawObject object) {
300 for (auto elt : pointers_) {
301 if (elt == object) {
302 return true;
303 }
304 }
305 return false;
306 }
307
308 private:
309 std::vector<RawObject> pointers_;
310};
311
312// Creates a temporary directory and cleans it up when the object is destroyed.
313class TemporaryDirectory {
314 public:
315 TemporaryDirectory();
316 ~TemporaryDirectory();
317
318 std::string path;
319};
320
321const uword kHighbitUword = uword{1} << (kBitsPerWord - 1);
322
323} // namespace testing
324} // namespace py