mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-05-18 03:46:39 +00:00

Modify OpenOptions enum to open the future path into synchronizing vFile:open bits with GDB. Currently, LLDB and GDB use different flag models effectively making it impossible to match bits. Notably, LLDB uses two bits to indicate read and write status, and uses union of both for read/write. GDB uses a value of 0 for read-only, 1 for write-only and 2 for read/write. In order to future-proof the code for the GDB variant: 1. Add a distinct eOpenOptionReadWrite constant to be used instead of (eOpenOptionRead | eOpenOptionWrite) when R/W access is required. 2. Rename eOpenOptionRead and eOpenOptionWrite to eOpenOptionReadOnly and eOpenOptionWriteOnly respectively, to make it clear that they do not mean to be combined and require update to all call sites. 3. Use the intersection of all three flags when matching against the three possible values. This commit does not change the actual bits used by LLDB. Differential Revision: https://reviews.llvm.org/D106984
862 lines
30 KiB
C++
862 lines
30 KiB
C++
//===-- PythonDataObjectsTests.cpp ----------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
|
|
#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
|
|
#include "lldb/Host/File.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/lldb-enumerations.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
|
|
#include "PythonTestSuite.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::python;
|
|
using llvm::Error;
|
|
using llvm::Expected;
|
|
|
|
class PythonDataObjectsTest : public PythonTestSuite {
|
|
public:
|
|
void SetUp() override {
|
|
PythonTestSuite::SetUp();
|
|
|
|
m_sys_module = unwrapIgnoringErrors(PythonModule::Import("sys"));
|
|
m_main_module = PythonModule::MainModule();
|
|
m_builtins_module = PythonModule::BuiltinsModule();
|
|
}
|
|
|
|
void TearDown() override {
|
|
m_sys_module.Reset();
|
|
m_main_module.Reset();
|
|
m_builtins_module.Reset();
|
|
|
|
PythonTestSuite::TearDown();
|
|
}
|
|
|
|
protected:
|
|
PythonModule m_sys_module;
|
|
PythonModule m_main_module;
|
|
PythonModule m_builtins_module;
|
|
};
|
|
|
|
TEST_F(PythonDataObjectsTest, TestOwnedReferences) {
|
|
// After creating a new object, the refcount should be >= 1
|
|
PyObject *obj = PyLong_FromLong(3);
|
|
Py_ssize_t original_refcnt = obj->ob_refcnt;
|
|
EXPECT_LE(1, original_refcnt);
|
|
|
|
// If we take an owned reference, the refcount should be the same
|
|
PythonObject owned_long(PyRefType::Owned, obj);
|
|
EXPECT_EQ(original_refcnt, owned_long.get()->ob_refcnt);
|
|
|
|
// Take another reference and verify that the refcount increases by 1
|
|
PythonObject strong_ref(owned_long);
|
|
EXPECT_EQ(original_refcnt + 1, strong_ref.get()->ob_refcnt);
|
|
|
|
// If we reset the first one, the refcount should be the original value.
|
|
owned_long.Reset();
|
|
EXPECT_EQ(original_refcnt, strong_ref.get()->ob_refcnt);
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestResetting) {
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
|
|
PyObject *new_dict = PyDict_New();
|
|
dict = Take<PythonDictionary>(new_dict);
|
|
EXPECT_EQ(new_dict, dict.get());
|
|
|
|
dict = Take<PythonDictionary>(PyDict_New());
|
|
EXPECT_NE(nullptr, dict.get());
|
|
dict.Reset();
|
|
EXPECT_EQ(nullptr, dict.get());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestBorrowedReferences) {
|
|
PythonInteger long_value(PyRefType::Owned, PyLong_FromLong(3));
|
|
Py_ssize_t original_refcnt = long_value.get()->ob_refcnt;
|
|
EXPECT_LE(1, original_refcnt);
|
|
|
|
PythonInteger borrowed_long(PyRefType::Borrowed, long_value.get());
|
|
EXPECT_EQ(original_refcnt + 1, borrowed_long.get()->ob_refcnt);
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionNoDot) {
|
|
PythonObject sys_module = m_main_module.ResolveName("sys");
|
|
EXPECT_EQ(m_sys_module.get(), sys_module.get());
|
|
EXPECT_TRUE(sys_module.IsAllocated());
|
|
EXPECT_TRUE(PythonModule::Check(sys_module.get()));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestModuleNameResolutionNoDot) {
|
|
PythonObject sys_path = m_sys_module.ResolveName("path");
|
|
PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
|
|
EXPECT_TRUE(sys_path.IsAllocated());
|
|
EXPECT_TRUE(sys_version_info.IsAllocated());
|
|
|
|
EXPECT_TRUE(PythonList::Check(sys_path.get()));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestTypeNameResolutionNoDot) {
|
|
PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
|
|
|
|
PythonObject version_info_type(PyRefType::Owned,
|
|
PyObject_Type(sys_version_info.get()));
|
|
EXPECT_TRUE(version_info_type.IsAllocated());
|
|
PythonObject major_version_field = version_info_type.ResolveName("major");
|
|
EXPECT_TRUE(major_version_field.IsAllocated());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestInstanceNameResolutionNoDot) {
|
|
PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
|
|
PythonObject major_version_field = sys_version_info.ResolveName("major");
|
|
PythonObject minor_version_field = sys_version_info.ResolveName("minor");
|
|
|
|
EXPECT_TRUE(major_version_field.IsAllocated());
|
|
EXPECT_TRUE(minor_version_field.IsAllocated());
|
|
|
|
auto major_version_value = As<long long>(major_version_field);
|
|
auto minor_version_value = As<long long>(minor_version_field);
|
|
|
|
EXPECT_THAT_EXPECTED(major_version_value, llvm::HasValue(PY_MAJOR_VERSION));
|
|
EXPECT_THAT_EXPECTED(minor_version_value, llvm::HasValue(PY_MINOR_VERSION));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionWithDot) {
|
|
PythonObject sys_path = m_main_module.ResolveName("sys.path");
|
|
EXPECT_TRUE(sys_path.IsAllocated());
|
|
EXPECT_TRUE(PythonList::Check(sys_path.get()));
|
|
|
|
auto version_major =
|
|
As<long long>(m_main_module.ResolveName("sys.version_info.major"));
|
|
|
|
auto version_minor =
|
|
As<long long>(m_main_module.ResolveName("sys.version_info.minor"));
|
|
|
|
EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
|
|
EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestDictionaryResolutionWithDot) {
|
|
// Make up a custom dictionary with "sys" pointing to the `sys` module.
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
dict.SetItemForKey(PythonString("sys"), m_sys_module);
|
|
|
|
// Now use that dictionary to resolve `sys.version_info.major`
|
|
auto version_major = As<long long>(
|
|
PythonObject::ResolveNameWithDictionary("sys.version_info.major", dict));
|
|
|
|
auto version_minor = As<long long>(
|
|
PythonObject::ResolveNameWithDictionary("sys.version_info.minor", dict));
|
|
|
|
EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
|
|
EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonInteger) {
|
|
// Test that integers behave correctly when wrapped by a PythonInteger.
|
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
// Verify that `PythonInt` works correctly when given a PyInt object.
|
|
// Note that PyInt doesn't exist in Python 3.x, so this is only for 2.x
|
|
PyObject *py_int = PyInt_FromLong(12);
|
|
EXPECT_TRUE(PythonInteger::Check(py_int));
|
|
PythonInteger python_int(PyRefType::Owned, py_int);
|
|
|
|
EXPECT_EQ(PyObjectType::Integer, python_int.GetObjectType());
|
|
auto python_int_value = As<long long>(python_int);
|
|
EXPECT_THAT_EXPECTED(python_int_value, llvm::HasValue(12));
|
|
#endif
|
|
|
|
// Verify that `PythonInteger` works correctly when given a PyLong object.
|
|
PyObject *py_long = PyLong_FromLong(12);
|
|
EXPECT_TRUE(PythonInteger::Check(py_long));
|
|
PythonInteger python_long(PyRefType::Owned, py_long);
|
|
EXPECT_EQ(PyObjectType::Integer, python_long.GetObjectType());
|
|
|
|
// Verify that you can reset the value and that it is reflected properly.
|
|
python_long.SetInteger(40);
|
|
auto e = As<long long>(python_long);
|
|
EXPECT_THAT_EXPECTED(e, llvm::HasValue(40));
|
|
|
|
// Test that creating a `PythonInteger` object works correctly with the
|
|
// int constructor.
|
|
PythonInteger constructed_int(7);
|
|
auto value = As<long long>(constructed_int);
|
|
EXPECT_THAT_EXPECTED(value, llvm::HasValue(7));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonBoolean) {
|
|
// Test PythonBoolean constructed from Py_True
|
|
EXPECT_TRUE(PythonBoolean::Check(Py_True));
|
|
PythonBoolean python_true(PyRefType::Owned, Py_True);
|
|
EXPECT_EQ(PyObjectType::Boolean, python_true.GetObjectType());
|
|
|
|
// Test PythonBoolean constructed from Py_False
|
|
EXPECT_TRUE(PythonBoolean::Check(Py_False));
|
|
PythonBoolean python_false(PyRefType::Owned, Py_False);
|
|
EXPECT_EQ(PyObjectType::Boolean, python_false.GetObjectType());
|
|
|
|
auto test_from_long = [](long value) {
|
|
PyObject *py_bool = PyBool_FromLong(value);
|
|
EXPECT_TRUE(PythonBoolean::Check(py_bool));
|
|
PythonBoolean python_boolean(PyRefType::Owned, py_bool);
|
|
EXPECT_EQ(PyObjectType::Boolean, python_boolean.GetObjectType());
|
|
EXPECT_EQ(bool(value), python_boolean.GetValue());
|
|
};
|
|
|
|
// Test PythonBoolean constructed from long integer values.
|
|
test_from_long(0); // Test 'false' value.
|
|
test_from_long(1); // Test 'true' value.
|
|
test_from_long(~0); // Any value != 0 is 'true'.
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonBytes) {
|
|
static const char *test_bytes = "PythonDataObjectsTest::TestPythonBytes";
|
|
PyObject *py_bytes = PyBytes_FromString(test_bytes);
|
|
EXPECT_TRUE(PythonBytes::Check(py_bytes));
|
|
PythonBytes python_bytes(PyRefType::Owned, py_bytes);
|
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
EXPECT_TRUE(PythonString::Check(py_bytes));
|
|
EXPECT_EQ(PyObjectType::String, python_bytes.GetObjectType());
|
|
#else
|
|
EXPECT_FALSE(PythonString::Check(py_bytes));
|
|
EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
|
|
#endif
|
|
|
|
llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes();
|
|
EXPECT_EQ(bytes.size(), strlen(test_bytes));
|
|
EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size()));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonByteArray) {
|
|
static const char *test_bytes = "PythonDataObjectsTest::TestPythonByteArray";
|
|
llvm::StringRef orig_bytes(test_bytes);
|
|
PyObject *py_bytes =
|
|
PyByteArray_FromStringAndSize(test_bytes, orig_bytes.size());
|
|
EXPECT_TRUE(PythonByteArray::Check(py_bytes));
|
|
PythonByteArray python_bytes(PyRefType::Owned, py_bytes);
|
|
EXPECT_EQ(PyObjectType::ByteArray, python_bytes.GetObjectType());
|
|
|
|
llvm::ArrayRef<uint8_t> after_bytes = python_bytes.GetBytes();
|
|
EXPECT_EQ(after_bytes.size(), orig_bytes.size());
|
|
EXPECT_EQ(0, ::memcmp(orig_bytes.data(), test_bytes, orig_bytes.size()));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonString) {
|
|
// Test that strings behave correctly when wrapped by a PythonString.
|
|
|
|
static const char *test_string = "PythonDataObjectsTest::TestPythonString1";
|
|
static const char *test_string2 = "PythonDataObjectsTest::TestPythonString2";
|
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
// Verify that `PythonString` works correctly when given a PyString object.
|
|
// Note that PyString doesn't exist in Python 3.x, so this is only for 2.x
|
|
PyObject *py_string = PyString_FromString(test_string);
|
|
EXPECT_TRUE(PythonString::Check(py_string));
|
|
PythonString python_string(PyRefType::Owned, py_string);
|
|
|
|
EXPECT_EQ(PyObjectType::String, python_string.GetObjectType());
|
|
EXPECT_STREQ(test_string, python_string.GetString().data());
|
|
#else
|
|
// Verify that `PythonString` works correctly when given a PyUnicode object.
|
|
PyObject *py_unicode = PyUnicode_FromString(test_string);
|
|
EXPECT_TRUE(PythonString::Check(py_unicode));
|
|
PythonString python_unicode(PyRefType::Owned, py_unicode);
|
|
EXPECT_EQ(PyObjectType::String, python_unicode.GetObjectType());
|
|
EXPECT_STREQ(test_string, python_unicode.GetString().data());
|
|
#endif
|
|
|
|
// Test that creating a `PythonString` object works correctly with the
|
|
// string constructor
|
|
PythonString constructed_string(test_string2);
|
|
EXPECT_EQ(test_string2, constructed_string.GetString());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonStringToStr) {
|
|
const char *GetString = "PythonDataObjectsTest::TestPythonStringToStr";
|
|
|
|
PythonString str(GetString);
|
|
EXPECT_EQ(GetString, str.GetString());
|
|
|
|
PythonString str_str = str.Str();
|
|
EXPECT_EQ(GetString, str_str.GetString());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonIntegerToStr) {}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredInteger) {
|
|
PythonInteger integer(7);
|
|
auto int_sp = integer.CreateStructuredInteger();
|
|
EXPECT_EQ(7U, int_sp->GetValue());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonStringToStructuredString) {
|
|
static const char *test_string =
|
|
"PythonDataObjectsTest::TestPythonStringToStructuredString";
|
|
PythonString constructed_string(test_string);
|
|
auto string_sp = constructed_string.CreateStructuredString();
|
|
EXPECT_EQ(test_string, string_sp->GetStringValue());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonListValueEquality) {
|
|
// Test that a list which is built through the native
|
|
// Python API behaves correctly when wrapped by a PythonList.
|
|
static const unsigned list_size = 2;
|
|
static const long long_value0 = 5;
|
|
static const char *const string_value1 = "String Index 1";
|
|
|
|
PyObject *py_list = PyList_New(2);
|
|
EXPECT_TRUE(PythonList::Check(py_list));
|
|
PythonList list(PyRefType::Owned, py_list);
|
|
|
|
PythonObject list_items[list_size];
|
|
list_items[0] = PythonInteger(long_value0);
|
|
list_items[1] = PythonString(string_value1);
|
|
|
|
for (unsigned i = 0; i < list_size; ++i)
|
|
list.SetItemAtIndex(i, list_items[i]);
|
|
|
|
EXPECT_EQ(list_size, list.GetSize());
|
|
EXPECT_EQ(PyObjectType::List, list.GetObjectType());
|
|
|
|
// Verify that the values match
|
|
PythonObject chk_value1 = list.GetItemAtIndex(0);
|
|
PythonObject chk_value2 = list.GetItemAtIndex(1);
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
|
|
|
PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
|
|
|
auto chkint = As<long long>(chk_value1);
|
|
ASSERT_THAT_EXPECTED(chkint, llvm::HasValue(long_value0));
|
|
EXPECT_EQ(string_value1, chk_str.GetString());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonListManipulation) {
|
|
// Test that manipulation of a PythonList behaves correctly when
|
|
// wrapped by a PythonDictionary.
|
|
|
|
static const long long_value0 = 5;
|
|
static const char *const string_value1 = "String Index 1";
|
|
|
|
PythonList list(PyInitialValue::Empty);
|
|
PythonInteger integer(long_value0);
|
|
PythonString string(string_value1);
|
|
|
|
list.AppendItem(integer);
|
|
list.AppendItem(string);
|
|
EXPECT_EQ(2U, list.GetSize());
|
|
|
|
// Verify that the values match
|
|
PythonObject chk_value1 = list.GetItemAtIndex(0);
|
|
PythonObject chk_value2 = list.GetItemAtIndex(1);
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
|
|
|
PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
|
|
|
auto e = As<long long>(chk_int);
|
|
EXPECT_THAT_EXPECTED(e, llvm::HasValue(long_value0));
|
|
EXPECT_EQ(string_value1, chk_str.GetString());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonListToStructuredList) {
|
|
static const long long_value0 = 5;
|
|
static const char *const string_value1 = "String Index 1";
|
|
|
|
PythonList list(PyInitialValue::Empty);
|
|
list.AppendItem(PythonInteger(long_value0));
|
|
list.AppendItem(PythonString(string_value1));
|
|
|
|
auto array_sp = list.CreateStructuredArray();
|
|
EXPECT_EQ(lldb::eStructuredDataTypeInteger,
|
|
array_sp->GetItemAtIndex(0)->GetType());
|
|
EXPECT_EQ(lldb::eStructuredDataTypeString,
|
|
array_sp->GetItemAtIndex(1)->GetType());
|
|
|
|
auto int_sp = array_sp->GetItemAtIndex(0)->GetAsInteger();
|
|
auto string_sp = array_sp->GetItemAtIndex(1)->GetAsString();
|
|
|
|
EXPECT_EQ(long_value0, long(int_sp->GetValue()));
|
|
EXPECT_EQ(string_value1, string_sp->GetValue());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleSize) {
|
|
PythonTuple tuple(PyInitialValue::Empty);
|
|
EXPECT_EQ(0U, tuple.GetSize());
|
|
|
|
tuple = PythonTuple(3);
|
|
EXPECT_EQ(3U, tuple.GetSize());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleValues) {
|
|
PythonTuple tuple(3);
|
|
|
|
PythonInteger int_value(1);
|
|
PythonString string_value("Test");
|
|
PythonObject none_value(PyRefType::Borrowed, Py_None);
|
|
|
|
tuple.SetItemAtIndex(0, int_value);
|
|
tuple.SetItemAtIndex(1, string_value);
|
|
tuple.SetItemAtIndex(2, none_value);
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
|
|
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
|
|
EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList) {
|
|
PythonInteger int_value(1);
|
|
PythonString string_value("Test");
|
|
PythonObject none_value(PyRefType::Borrowed, Py_None);
|
|
PythonTuple tuple{int_value, string_value, none_value};
|
|
EXPECT_EQ(3U, tuple.GetSize());
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
|
|
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
|
|
EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList2) {
|
|
PythonInteger int_value(1);
|
|
PythonString string_value("Test");
|
|
PythonObject none_value(PyRefType::Borrowed, Py_None);
|
|
|
|
PythonTuple tuple{int_value.get(), string_value.get(), none_value.get()};
|
|
EXPECT_EQ(3U, tuple.GetSize());
|
|
|
|
EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
|
|
EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
|
|
EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonTupleToStructuredList) {
|
|
PythonInteger int_value(1);
|
|
PythonString string_value("Test");
|
|
|
|
PythonTuple tuple{int_value.get(), string_value.get()};
|
|
|
|
auto array_sp = tuple.CreateStructuredArray();
|
|
EXPECT_EQ(tuple.GetSize(), array_sp->GetSize());
|
|
EXPECT_EQ(lldb::eStructuredDataTypeInteger,
|
|
array_sp->GetItemAtIndex(0)->GetType());
|
|
EXPECT_EQ(lldb::eStructuredDataTypeString,
|
|
array_sp->GetItemAtIndex(1)->GetType());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality) {
|
|
// Test that a dictionary which is built through the native
|
|
// Python API behaves correctly when wrapped by a PythonDictionary.
|
|
static const unsigned dict_entries = 2;
|
|
const char *key_0 = "Key 0";
|
|
int key_1 = 1;
|
|
const int value_0 = 0;
|
|
const char *value_1 = "Value 1";
|
|
|
|
PythonObject py_keys[dict_entries];
|
|
PythonObject py_values[dict_entries];
|
|
|
|
py_keys[0] = PythonString(key_0);
|
|
py_keys[1] = PythonInteger(key_1);
|
|
py_values[0] = PythonInteger(value_0);
|
|
py_values[1] = PythonString(value_1);
|
|
|
|
PyObject *py_dict = PyDict_New();
|
|
EXPECT_TRUE(PythonDictionary::Check(py_dict));
|
|
PythonDictionary dict(PyRefType::Owned, py_dict);
|
|
|
|
for (unsigned i = 0; i < dict_entries; ++i)
|
|
PyDict_SetItem(py_dict, py_keys[i].get(), py_values[i].get());
|
|
EXPECT_EQ(dict.GetSize(), dict_entries);
|
|
EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
|
|
|
|
// Verify that the values match
|
|
PythonObject chk_value1 = dict.GetItemForKey(py_keys[0]);
|
|
PythonObject chk_value2 = dict.GetItemForKey(py_keys[1]);
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
|
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
|
auto chkint = As<long long>(chk_value1);
|
|
|
|
EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
|
|
EXPECT_EQ(value_1, chk_str.GetString());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation) {
|
|
// Test that manipulation of a dictionary behaves correctly when wrapped
|
|
// by a PythonDictionary.
|
|
static const unsigned dict_entries = 2;
|
|
|
|
const char *const key_0 = "Key 0";
|
|
const char *const key_1 = "Key 1";
|
|
const long value_0 = 1;
|
|
const char *const value_1 = "Value 1";
|
|
|
|
PythonString keys[dict_entries];
|
|
PythonObject values[dict_entries];
|
|
|
|
keys[0] = PythonString(key_0);
|
|
keys[1] = PythonString(key_1);
|
|
values[0] = PythonInteger(value_0);
|
|
values[1] = PythonString(value_1);
|
|
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
for (int i = 0; i < 2; ++i)
|
|
dict.SetItemForKey(keys[i], values[i]);
|
|
|
|
EXPECT_EQ(dict_entries, dict.GetSize());
|
|
|
|
// Verify that the keys and values match
|
|
PythonObject chk_value1 = dict.GetItemForKey(keys[0]);
|
|
PythonObject chk_value2 = dict.GetItemForKey(keys[1]);
|
|
EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
|
|
EXPECT_TRUE(PythonString::Check(chk_value2.get()));
|
|
|
|
auto chkint = As<long long>(chk_value1);
|
|
PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
|
|
|
|
EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
|
|
EXPECT_EQ(value_1, chk_str.GetString());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary) {
|
|
static const char *const string_key0 = "String Key 0";
|
|
static const char *const string_key1 = "String Key 1";
|
|
|
|
static const char *const string_value0 = "String Value 0";
|
|
static const long int_value1 = 7;
|
|
|
|
PythonDictionary dict(PyInitialValue::Empty);
|
|
dict.SetItemForKey(PythonString(string_key0), PythonString(string_value0));
|
|
dict.SetItemForKey(PythonString(string_key1), PythonInteger(int_value1));
|
|
|
|
auto dict_sp = dict.CreateStructuredDictionary();
|
|
EXPECT_EQ(2U, dict_sp->GetSize());
|
|
|
|
EXPECT_TRUE(dict_sp->HasKey(string_key0));
|
|
EXPECT_TRUE(dict_sp->HasKey(string_key1));
|
|
|
|
auto string_sp = dict_sp->GetValueForKey(string_key0)->GetAsString();
|
|
auto int_sp = dict_sp->GetValueForKey(string_key1)->GetAsInteger();
|
|
|
|
EXPECT_EQ(string_value0, string_sp->GetValue());
|
|
EXPECT_EQ(int_value1, long(int_sp->GetValue()));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonCallableCheck) {
|
|
PythonObject sys_exc_info = m_sys_module.ResolveName("exc_info");
|
|
PythonObject none(PyRefType::Borrowed, Py_None);
|
|
|
|
EXPECT_TRUE(PythonCallable::Check(sys_exc_info.get()));
|
|
EXPECT_FALSE(PythonCallable::Check(none.get()));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke) {
|
|
auto list = m_builtins_module.ResolveName("list").AsType<PythonCallable>();
|
|
PythonInteger one(1);
|
|
PythonString two("two");
|
|
PythonTuple three = {one, two};
|
|
|
|
PythonTuple tuple_to_convert = {one, two, three};
|
|
PythonObject result = list({tuple_to_convert});
|
|
|
|
EXPECT_TRUE(PythonList::Check(result.get()));
|
|
auto list_result = result.AsType<PythonList>();
|
|
EXPECT_EQ(3U, list_result.GetSize());
|
|
EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get());
|
|
EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get());
|
|
EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get());
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestPythonFile) {
|
|
auto file = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
|
|
File::eOpenOptionReadOnly);
|
|
ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
|
|
auto py_file = PythonFile::FromFile(*file.get(), "r");
|
|
ASSERT_THAT_EXPECTED(py_file, llvm::Succeeded());
|
|
EXPECT_TRUE(PythonFile::Check(py_file.get().get()));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestObjectAttributes) {
|
|
PythonInteger py_int(42);
|
|
EXPECT_TRUE(py_int.HasAttribute("numerator"));
|
|
EXPECT_FALSE(py_int.HasAttribute("this_should_not_exist"));
|
|
|
|
auto numerator_attr = As<long long>(py_int.GetAttributeValue("numerator"));
|
|
|
|
EXPECT_THAT_EXPECTED(numerator_attr, llvm::HasValue(42));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestExtractingUInt64ThroughStructuredData) {
|
|
// Make up a custom dictionary with "sys" pointing to the `sys` module.
|
|
const char *key_name = "addr";
|
|
const uint64_t value = 0xf000000000000000ull;
|
|
PythonDictionary python_dict(PyInitialValue::Empty);
|
|
PythonInteger python_ull_value(PyRefType::Owned,
|
|
PyLong_FromUnsignedLongLong(value));
|
|
python_dict.SetItemForKey(PythonString(key_name), python_ull_value);
|
|
StructuredData::ObjectSP structured_data_sp =
|
|
python_dict.CreateStructuredObject();
|
|
EXPECT_TRUE((bool)structured_data_sp);
|
|
if (structured_data_sp) {
|
|
StructuredData::Dictionary *structured_dict_ptr =
|
|
structured_data_sp->GetAsDictionary();
|
|
EXPECT_TRUE(structured_dict_ptr != nullptr);
|
|
if (structured_dict_ptr) {
|
|
StructuredData::ObjectSP structured_addr_value_sp =
|
|
structured_dict_ptr->GetValueForKey(key_name);
|
|
EXPECT_TRUE((bool)structured_addr_value_sp);
|
|
const uint64_t extracted_value =
|
|
structured_addr_value_sp->GetIntegerValue(123);
|
|
EXPECT_TRUE(extracted_value == value);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestCallable) {
|
|
|
|
PythonDictionary globals(PyInitialValue::Empty);
|
|
auto builtins = PythonModule::BuiltinsModule();
|
|
llvm::Error error = globals.SetItem("__builtins__", builtins);
|
|
ASSERT_FALSE(error);
|
|
|
|
{
|
|
PyObject *o = PyRun_String("lambda x : x", Py_eval_input, globals.get(),
|
|
globals.get());
|
|
ASSERT_FALSE(o == NULL);
|
|
auto lambda = Take<PythonCallable>(o);
|
|
auto arginfo = lambda.GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
}
|
|
|
|
{
|
|
PyObject *o = PyRun_String("lambda x,y=0: x", Py_eval_input, globals.get(),
|
|
globals.get());
|
|
ASSERT_FALSE(o == NULL);
|
|
auto lambda = Take<PythonCallable>(o);
|
|
auto arginfo = lambda.GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 2u);
|
|
}
|
|
|
|
{
|
|
PyObject *o = PyRun_String("lambda x,y=0, **kw: x", Py_eval_input,
|
|
globals.get(), globals.get());
|
|
ASSERT_FALSE(o == NULL);
|
|
auto lambda = Take<PythonCallable>(o);
|
|
auto arginfo = lambda.GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 2u);
|
|
}
|
|
|
|
{
|
|
PyObject *o = PyRun_String("lambda x,y,*a: x", Py_eval_input, globals.get(),
|
|
globals.get());
|
|
ASSERT_FALSE(o == NULL);
|
|
auto lambda = Take<PythonCallable>(o);
|
|
auto arginfo = lambda.GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args,
|
|
PythonCallable::ArgInfo::UNBOUNDED);
|
|
}
|
|
|
|
{
|
|
PyObject *o = PyRun_String("lambda x,y,*a,**kw: x", Py_eval_input,
|
|
globals.get(), globals.get());
|
|
ASSERT_FALSE(o == NULL);
|
|
auto lambda = Take<PythonCallable>(o);
|
|
auto arginfo = lambda.GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args,
|
|
PythonCallable::ArgInfo::UNBOUNDED);
|
|
}
|
|
|
|
{
|
|
const char *script = R"(
|
|
class Foo:
|
|
def bar(self, x):
|
|
return x
|
|
@classmethod
|
|
def classbar(cls, x):
|
|
return x
|
|
@staticmethod
|
|
def staticbar(x):
|
|
return x
|
|
def __call__(self, x):
|
|
return x
|
|
obj = Foo()
|
|
bar_bound = Foo().bar
|
|
bar_class = Foo().classbar
|
|
bar_static = Foo().staticbar
|
|
bar_unbound = Foo.bar
|
|
|
|
|
|
class OldStyle:
|
|
def __init__(self, one, two, three):
|
|
pass
|
|
|
|
class NewStyle(object):
|
|
def __init__(self, one, two, three):
|
|
pass
|
|
|
|
)";
|
|
PyObject *o =
|
|
PyRun_String(script, Py_file_input, globals.get(), globals.get());
|
|
ASSERT_FALSE(o == NULL);
|
|
Take<PythonObject>(o);
|
|
|
|
auto bar_bound = As<PythonCallable>(globals.GetItem("bar_bound"));
|
|
ASSERT_THAT_EXPECTED(bar_bound, llvm::Succeeded());
|
|
auto arginfo = bar_bound.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
|
|
auto bar_unbound = As<PythonCallable>(globals.GetItem("bar_unbound"));
|
|
ASSERT_THAT_EXPECTED(bar_unbound, llvm::Succeeded());
|
|
arginfo = bar_unbound.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 2u);
|
|
|
|
auto bar_class = As<PythonCallable>(globals.GetItem("bar_class"));
|
|
ASSERT_THAT_EXPECTED(bar_class, llvm::Succeeded());
|
|
arginfo = bar_class.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
|
|
auto bar_static = As<PythonCallable>(globals.GetItem("bar_static"));
|
|
ASSERT_THAT_EXPECTED(bar_static, llvm::Succeeded());
|
|
arginfo = bar_static.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
|
|
auto obj = As<PythonCallable>(globals.GetItem("obj"));
|
|
ASSERT_THAT_EXPECTED(obj, llvm::Succeeded());
|
|
arginfo = obj.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
|
|
auto oldstyle = As<PythonCallable>(globals.GetItem("OldStyle"));
|
|
ASSERT_THAT_EXPECTED(oldstyle, llvm::Succeeded());
|
|
arginfo = oldstyle.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 3u);
|
|
|
|
auto newstyle = As<PythonCallable>(globals.GetItem("NewStyle"));
|
|
ASSERT_THAT_EXPECTED(newstyle, llvm::Succeeded());
|
|
arginfo = newstyle.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 3u);
|
|
}
|
|
|
|
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
|
|
|
|
// the old implementation of GetArgInfo just doesn't work on builtins.
|
|
|
|
{
|
|
auto builtins = PythonModule::BuiltinsModule();
|
|
auto hex = As<PythonCallable>(builtins.GetAttribute("hex"));
|
|
ASSERT_THAT_EXPECTED(hex, llvm::Succeeded());
|
|
auto arginfo = hex.get().GetArgInfo();
|
|
ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
|
|
EXPECT_EQ(arginfo.get().max_positional_args, 1u);
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestScript) {
|
|
|
|
static const char script[] = R"(
|
|
def factorial(n):
|
|
if n > 1:
|
|
return n * factorial(n-1)
|
|
else:
|
|
return 1;
|
|
main = factorial
|
|
)";
|
|
|
|
PythonScript factorial(script);
|
|
|
|
EXPECT_THAT_EXPECTED(As<long long>(factorial(5ll)), llvm::HasValue(120));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestExceptions) {
|
|
|
|
static const char script[] = R"(
|
|
def foo():
|
|
return bar()
|
|
def bar():
|
|
return baz()
|
|
def baz():
|
|
return 1 / 0
|
|
main = foo
|
|
)";
|
|
|
|
PythonScript foo(script);
|
|
|
|
EXPECT_THAT_EXPECTED(
|
|
foo(), llvm::Failed<PythonException>(testing::Property(
|
|
&PythonException::ReadBacktrace,
|
|
testing::AllOf(testing::ContainsRegex("line 3, in foo"),
|
|
testing::ContainsRegex("line 5, in bar"),
|
|
testing::ContainsRegex("line 7, in baz"),
|
|
testing::ContainsRegex("ZeroDivisionError")))));
|
|
|
|
static const char script2[] = R"(
|
|
class MyError(Exception):
|
|
def __str__(self):
|
|
return self.my_message
|
|
|
|
def main():
|
|
raise MyError("lol")
|
|
|
|
)";
|
|
|
|
PythonScript lol(script2);
|
|
|
|
EXPECT_THAT_EXPECTED(lol(),
|
|
llvm::Failed<PythonException>(testing::Property(
|
|
&PythonException::ReadBacktrace,
|
|
testing::ContainsRegex("unprintable MyError"))));
|
|
}
|
|
|
|
TEST_F(PythonDataObjectsTest, TestRun) {
|
|
|
|
PythonDictionary globals(PyInitialValue::Empty);
|
|
|
|
auto x = As<long long>(runStringOneLine("40 + 2", globals, globals));
|
|
ASSERT_THAT_EXPECTED(x, llvm::Succeeded());
|
|
EXPECT_EQ(x.get(), 42l);
|
|
|
|
Expected<PythonObject> r = runStringOneLine("n = 42", globals, globals);
|
|
ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
|
|
auto y = As<long long>(globals.GetItem("n"));
|
|
ASSERT_THAT_EXPECTED(y, llvm::Succeeded());
|
|
EXPECT_EQ(y.get(), 42l);
|
|
|
|
const char script[] = R"(
|
|
def foobar():
|
|
return "foo" + "bar" + "baz"
|
|
g = foobar()
|
|
)";
|
|
|
|
r = runStringMultiLine(script, globals, globals);
|
|
ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
|
|
auto g = As<std::string>(globals.GetItem("g"));
|
|
ASSERT_THAT_EXPECTED(g, llvm::HasValue("foobarbaz"));
|
|
}
|