this repo has no description
at trunk 324 lines 11 kB view raw
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