1//===-- PythonDataObjectsTests.cpp ----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
10#include "gtest/gtest.h"
11
12#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
13#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
14#include "TestingSupport/SubsystemRAII.h"
15#include "lldb/Host/File.h"
16#include "lldb/Host/FileSystem.h"
17#include "lldb/Host/HostInfo.h"
18#include "lldb/lldb-enumerations.h"
19#include "llvm/Testing/Support/Error.h"
20
21#include "PythonTestSuite.h"
22
23#include <variant>
24
25using namespace lldb_private;
26using namespace lldb_private::python;
27using llvm::Expected;
28
29class PythonDataObjectsTest : public PythonTestSuite {
30 SubsystemRAII<FileSystem> subsystems;
31
32public:
33 void SetUp() override {
34 PythonTestSuite::SetUp();
35
36 m_sys_module = unwrapIgnoringErrors(expected: PythonModule::Import(name: "sys"));
37 m_main_module = PythonModule::MainModule();
38 m_builtins_module = PythonModule::BuiltinsModule();
39 }
40
41 void TearDown() override {
42 m_sys_module.Reset();
43 m_main_module.Reset();
44 m_builtins_module.Reset();
45
46 PythonTestSuite::TearDown();
47 }
48
49protected:
50 PythonModule m_sys_module;
51 PythonModule m_main_module;
52 PythonModule m_builtins_module;
53};
54
55TEST_F(PythonDataObjectsTest, TestOwnedReferences) {
56 // After creating a new object, the refcount should be >= 1
57 PyObject *obj = PyBytes_FromString("foo");
58 Py_ssize_t original_refcnt = Py_REFCNT(obj);
59 EXPECT_LE(1, original_refcnt);
60
61 // If we take an owned reference, the refcount should be the same
62 PythonObject owned(PyRefType::Owned, obj);
63 Py_ssize_t owned_refcnt = Py_REFCNT(owned.get());
64 EXPECT_EQ(original_refcnt, owned_refcnt);
65
66 // Take another reference and verify that the refcount increases by 1
67 PythonObject strong_ref(owned);
68 Py_ssize_t strong_refcnt = Py_REFCNT(strong_ref.get());
69 EXPECT_EQ(original_refcnt + 1, strong_refcnt);
70
71 // If we reset the first one, the refcount should be the original value.
72 owned.Reset();
73 strong_refcnt = Py_REFCNT(strong_ref.get());
74 EXPECT_EQ(original_refcnt, strong_refcnt);
75}
76
77TEST_F(PythonDataObjectsTest, TestResetting) {
78 PythonDictionary dict(PyInitialValue::Empty);
79
80 PyObject *new_dict = PyDict_New();
81 dict = Take<PythonDictionary>(obj: new_dict);
82 EXPECT_EQ(new_dict, dict.get());
83
84 dict = Take<PythonDictionary>(obj: PyDict_New());
85 EXPECT_NE(nullptr, dict.get());
86 dict.Reset();
87 EXPECT_EQ(nullptr, dict.get());
88}
89
90TEST_F(PythonDataObjectsTest, TestBorrowedReferences) {
91 PythonByteArray byte_value(PyRefType::Owned,
92 PyByteArray_FromStringAndSize("foo", 3));
93 Py_ssize_t original_refcnt = Py_REFCNT(byte_value.get());
94 EXPECT_LE(1, original_refcnt);
95
96 PythonByteArray borrowed_byte(PyRefType::Borrowed, byte_value.get());
97 Py_ssize_t borrowed_refcnt = Py_REFCNT(borrowed_byte.get());
98
99 EXPECT_EQ(original_refcnt + 1, borrowed_refcnt);
100}
101
102TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionNoDot) {
103 PythonObject sys_module = m_main_module.ResolveName(name: "sys");
104 EXPECT_EQ(m_sys_module.get(), sys_module.get());
105 EXPECT_TRUE(sys_module.IsAllocated());
106 EXPECT_TRUE(PythonModule::Check(sys_module.get()));
107}
108
109TEST_F(PythonDataObjectsTest, TestModuleNameResolutionNoDot) {
110 PythonObject sys_path = m_sys_module.ResolveName(name: "path");
111 PythonObject sys_version_info = m_sys_module.ResolveName(name: "version_info");
112 EXPECT_TRUE(sys_path.IsAllocated());
113 EXPECT_TRUE(sys_version_info.IsAllocated());
114
115 EXPECT_TRUE(PythonList::Check(sys_path.get()));
116}
117
118TEST_F(PythonDataObjectsTest, TestTypeNameResolutionNoDot) {
119 PythonObject sys_version_info = m_sys_module.ResolveName(name: "version_info");
120
121 PythonObject version_info_type(PyRefType::Owned,
122 PyObject_Type(o: sys_version_info.get()));
123 EXPECT_TRUE(version_info_type.IsAllocated());
124 PythonObject major_version_field = version_info_type.ResolveName(name: "major");
125 EXPECT_TRUE(major_version_field.IsAllocated());
126}
127
128TEST_F(PythonDataObjectsTest, TestInstanceNameResolutionNoDot) {
129 PythonObject sys_version_info = m_sys_module.ResolveName(name: "version_info");
130 PythonObject major_version_field = sys_version_info.ResolveName(name: "major");
131 PythonObject minor_version_field = sys_version_info.ResolveName(name: "minor");
132
133 EXPECT_TRUE(major_version_field.IsAllocated());
134 EXPECT_TRUE(minor_version_field.IsAllocated());
135
136 auto major_version_value = As<long long>(obj: major_version_field);
137 auto minor_version_value = As<long long>(obj: minor_version_field);
138
139 EXPECT_THAT_EXPECTED(major_version_value, llvm::HasValue(PY_MAJOR_VERSION));
140 EXPECT_THAT_EXPECTED(minor_version_value, llvm::HasValue(PY_MINOR_VERSION));
141}
142
143TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionWithDot) {
144 PythonObject sys_path = m_main_module.ResolveName(name: "sys.path");
145 EXPECT_TRUE(sys_path.IsAllocated());
146 EXPECT_TRUE(PythonList::Check(sys_path.get()));
147
148 auto version_major =
149 As<long long>(obj: m_main_module.ResolveName(name: "sys.version_info.major"));
150
151 auto version_minor =
152 As<long long>(obj: m_main_module.ResolveName(name: "sys.version_info.minor"));
153
154 EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
155 EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
156}
157
158TEST_F(PythonDataObjectsTest, TestDictionaryResolutionWithDot) {
159 // Make up a custom dictionary with "sys" pointing to the `sys` module.
160 PythonDictionary dict(PyInitialValue::Empty);
161 dict.SetItemForKey(key: PythonString("sys"), value: m_sys_module);
162
163 // Now use that dictionary to resolve `sys.version_info.major`
164 auto version_major = As<long long>(
165 obj: PythonObject::ResolveNameWithDictionary(name: "sys.version_info.major", dict));
166
167 auto version_minor = As<long long>(
168 obj: PythonObject::ResolveNameWithDictionary(name: "sys.version_info.minor", dict));
169
170 EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
171 EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
172}
173
174TEST_F(PythonDataObjectsTest, TestPythonInteger) {
175 // Test that integers behave correctly when wrapped by a PythonInteger.
176
177 // Verify that `PythonInteger` works correctly when given a PyLong object.
178 PyObject *py_long = PyLong_FromLong(12);
179 EXPECT_TRUE(PythonInteger::Check(py_long));
180 PythonInteger python_long(PyRefType::Owned, py_long);
181 EXPECT_EQ(PyObjectType::Integer, python_long.GetObjectType());
182
183 // Verify that you can reset the value and that it is reflected properly.
184 python_long.SetInteger(40);
185 auto e = As<long long>(obj: python_long);
186 EXPECT_THAT_EXPECTED(e, llvm::HasValue(40));
187
188 // Test that creating a `PythonInteger` object works correctly with the
189 // int constructor.
190 PythonInteger constructed_int(7);
191 auto value = As<long long>(obj: constructed_int);
192 EXPECT_THAT_EXPECTED(value, llvm::HasValue(7));
193}
194
195TEST_F(PythonDataObjectsTest, TestPythonBoolean) {
196 // Test PythonBoolean constructed from Py_True
197 EXPECT_TRUE(PythonBoolean::Check(Py_True));
198 PythonBoolean python_true(PyRefType::Owned, Py_True);
199 EXPECT_EQ(PyObjectType::Boolean, python_true.GetObjectType());
200
201 // Test PythonBoolean constructed from Py_False
202 EXPECT_TRUE(PythonBoolean::Check(Py_False));
203 PythonBoolean python_false(PyRefType::Owned, Py_False);
204 EXPECT_EQ(PyObjectType::Boolean, python_false.GetObjectType());
205
206 auto test_from_long = [](long value) {
207 PyObject *py_bool = PyBool_FromLong(value);
208 EXPECT_TRUE(PythonBoolean::Check(py_bool));
209 PythonBoolean python_boolean(PyRefType::Owned, py_bool);
210 EXPECT_EQ(PyObjectType::Boolean, python_boolean.GetObjectType());
211 EXPECT_EQ(bool(value), python_boolean.GetValue());
212 };
213
214 // Test PythonBoolean constructed from long integer values.
215 test_from_long(0); // Test 'false' value.
216 test_from_long(1); // Test 'true' value.
217 test_from_long(~0); // Any value != 0 is 'true'.
218}
219
220TEST_F(PythonDataObjectsTest, TestPythonBytes) {
221 static const char *test_bytes = "PythonDataObjectsTest::TestPythonBytes";
222 PyObject *py_bytes = PyBytes_FromString(test_bytes);
223 EXPECT_TRUE(PythonBytes::Check(py_bytes));
224 PythonBytes python_bytes(PyRefType::Owned, py_bytes);
225
226 EXPECT_FALSE(PythonString::Check(py_bytes));
227 EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
228
229 llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes();
230 EXPECT_EQ(bytes.size(), strlen(test_bytes));
231 EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size()));
232}
233
234TEST_F(PythonDataObjectsTest, TestPythonByteArray) {
235 static const char *test_bytes = "PythonDataObjectsTest::TestPythonByteArray";
236 llvm::StringRef orig_bytes(test_bytes);
237 PyObject *py_bytes =
238 PyByteArray_FromStringAndSize(test_bytes, orig_bytes.size());
239 EXPECT_TRUE(PythonByteArray::Check(py_bytes));
240 PythonByteArray python_bytes(PyRefType::Owned, py_bytes);
241 EXPECT_EQ(PyObjectType::ByteArray, python_bytes.GetObjectType());
242
243 llvm::ArrayRef<uint8_t> after_bytes = python_bytes.GetBytes();
244 EXPECT_EQ(after_bytes.size(), orig_bytes.size());
245 EXPECT_EQ(0, ::memcmp(orig_bytes.data(), test_bytes, orig_bytes.size()));
246}
247
248TEST_F(PythonDataObjectsTest, TestPythonString) {
249 // Test that strings behave correctly when wrapped by a PythonString.
250
251 static const char *test_string = "PythonDataObjectsTest::TestPythonString1";
252 static const char *test_string2 = "PythonDataObjectsTest::TestPythonString2";
253
254 // Verify that `PythonString` works correctly when given a PyUnicode object.
255 PyObject *py_unicode = PyUnicode_FromString(u: test_string);
256 EXPECT_TRUE(PythonString::Check(py_unicode));
257 PythonString python_unicode(PyRefType::Owned, py_unicode);
258 EXPECT_EQ(PyObjectType::String, python_unicode.GetObjectType());
259 EXPECT_STREQ(test_string, python_unicode.GetString().data());
260
261 // Test that creating a `PythonString` object works correctly with the
262 // string constructor
263 PythonString constructed_string(test_string2);
264 EXPECT_EQ(test_string2, constructed_string.GetString());
265}
266
267TEST_F(PythonDataObjectsTest, TestPythonStringToStr) {
268 const char *GetString = "PythonDataObjectsTest::TestPythonStringToStr";
269
270 PythonString str(GetString);
271 EXPECT_EQ(GetString, str.GetString());
272
273 PythonString str_str = str.Str();
274 EXPECT_EQ(GetString, str_str.GetString());
275}
276
277TEST_F(PythonDataObjectsTest, TestPythonIntegerToStr) {}
278
279TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredUnsignedInteger) {
280 PythonInteger integer(7);
281 auto int_sp = integer.CreateStructuredInteger();
282 EXPECT_TRUE(
283 std::holds_alternative<StructuredData::UnsignedIntegerSP>(int_sp));
284 StructuredData::UnsignedIntegerSP uint_sp =
285 std::get<StructuredData::UnsignedIntegerSP>(v&: int_sp);
286 EXPECT_EQ(7U, uint_sp->GetValue());
287}
288
289TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredSignedInteger) {
290 PythonInteger integer(-42);
291 auto int_sp = integer.CreateStructuredInteger();
292 EXPECT_TRUE(std::holds_alternative<StructuredData::SignedIntegerSP>(int_sp));
293 StructuredData::SignedIntegerSP sint_sp =
294 std::get<StructuredData::SignedIntegerSP>(v&: int_sp);
295 EXPECT_EQ(-42, sint_sp->GetValue());
296}
297
298TEST_F(PythonDataObjectsTest, TestPythonStringToStructuredString) {
299 static const char *test_string =
300 "PythonDataObjectsTest::TestPythonStringToStructuredString";
301 PythonString constructed_string(test_string);
302 auto string_sp = constructed_string.CreateStructuredString();
303 EXPECT_EQ(test_string, string_sp->GetStringValue());
304}
305
306TEST_F(PythonDataObjectsTest, TestPythonListValueEquality) {
307 // Test that a list which is built through the native
308 // Python API behaves correctly when wrapped by a PythonList.
309 static const unsigned list_size = 2;
310 static const long long_value0 = 5;
311 static const char *const string_value1 = "String Index 1";
312
313 PyObject *py_list = PyList_New(size: 2);
314 EXPECT_TRUE(PythonList::Check(py_list));
315 PythonList list(PyRefType::Owned, py_list);
316
317 PythonObject list_items[list_size];
318 list_items[0] = PythonInteger(long_value0);
319 list_items[1] = PythonString(string_value1);
320
321 for (unsigned i = 0; i < list_size; ++i)
322 list.SetItemAtIndex(index: i, object: list_items[i]);
323
324 EXPECT_EQ(list_size, list.GetSize());
325 EXPECT_EQ(PyObjectType::List, list.GetObjectType());
326
327 // Verify that the values match
328 PythonObject chk_value1 = list.GetItemAtIndex(index: 0);
329 PythonObject chk_value2 = list.GetItemAtIndex(index: 1);
330 EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
331 EXPECT_TRUE(PythonString::Check(chk_value2.get()));
332
333 PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
334 PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
335
336 auto chkint = As<long long>(obj: chk_value1);
337 ASSERT_THAT_EXPECTED(chkint, llvm::HasValue(long_value0));
338 EXPECT_EQ(string_value1, chk_str.GetString());
339}
340
341TEST_F(PythonDataObjectsTest, TestPythonListManipulation) {
342 // Test that manipulation of a PythonList behaves correctly when
343 // wrapped by a PythonDictionary.
344
345 static const long long_value0 = 5;
346 static const char *const string_value1 = "String Index 1";
347
348 PythonList list(PyInitialValue::Empty);
349 PythonInteger integer(long_value0);
350 PythonString string(string_value1);
351
352 list.AppendItem(object: integer);
353 list.AppendItem(object: string);
354 EXPECT_EQ(2U, list.GetSize());
355
356 // Verify that the values match
357 PythonObject chk_value1 = list.GetItemAtIndex(index: 0);
358 PythonObject chk_value2 = list.GetItemAtIndex(index: 1);
359 EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
360 EXPECT_TRUE(PythonString::Check(chk_value2.get()));
361
362 PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
363 PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
364
365 auto e = As<long long>(obj: chk_int);
366 EXPECT_THAT_EXPECTED(e, llvm::HasValue(long_value0));
367 EXPECT_EQ(string_value1, chk_str.GetString());
368}
369
370TEST_F(PythonDataObjectsTest, TestPythonListToStructuredList) {
371 static const long long_value0 = 5;
372 static const char *const string_value1 = "String Index 1";
373
374 PythonList list(PyInitialValue::Empty);
375 list.AppendItem(object: PythonInteger(long_value0));
376 list.AppendItem(object: PythonString(string_value1));
377
378 auto array_sp = list.CreateStructuredArray();
379 EXPECT_EQ(lldb::eStructuredDataTypeInteger,
380 array_sp->GetItemAtIndex(0)->GetType());
381 EXPECT_EQ(lldb::eStructuredDataTypeString,
382 array_sp->GetItemAtIndex(1)->GetType());
383
384 auto int_sp = array_sp->GetItemAtIndex(idx: 0)->GetAsUnsignedInteger();
385 auto string_sp = array_sp->GetItemAtIndex(idx: 1)->GetAsString();
386
387 EXPECT_EQ(long_value0, long(int_sp->GetValue()));
388 EXPECT_EQ(string_value1, string_sp->GetValue());
389}
390
391TEST_F(PythonDataObjectsTest, TestPythonTupleSize) {
392 PythonTuple tuple(PyInitialValue::Empty);
393 EXPECT_EQ(0U, tuple.GetSize());
394
395 tuple = PythonTuple(3);
396 EXPECT_EQ(3U, tuple.GetSize());
397}
398
399TEST_F(PythonDataObjectsTest, TestPythonTupleValues) {
400 PythonTuple tuple(3);
401
402 PythonInteger int_value(1);
403 PythonString string_value("Test");
404 PythonObject none_value(PyRefType::Borrowed, Py_None);
405
406 tuple.SetItemAtIndex(index: 0, object: int_value);
407 tuple.SetItemAtIndex(index: 1, object: string_value);
408 tuple.SetItemAtIndex(index: 2, object: none_value);
409
410 EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
411 EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
412 EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
413}
414
415TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList) {
416 PythonInteger int_value(1);
417 PythonString string_value("Test");
418 PythonObject none_value(PyRefType::Borrowed, Py_None);
419 PythonTuple tuple{int_value, string_value, none_value};
420 EXPECT_EQ(3U, tuple.GetSize());
421
422 EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
423 EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
424 EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
425}
426
427TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList2) {
428 PythonInteger int_value(1);
429 PythonString string_value("Test");
430 PythonObject none_value(PyRefType::Borrowed, Py_None);
431
432 PythonTuple tuple{int_value.get(), string_value.get(), none_value.get()};
433 EXPECT_EQ(3U, tuple.GetSize());
434
435 EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
436 EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
437 EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
438}
439
440TEST_F(PythonDataObjectsTest, TestPythonTupleToStructuredList) {
441 PythonInteger int_value(1);
442 PythonString string_value("Test");
443
444 PythonTuple tuple{int_value.get(), string_value.get()};
445
446 auto array_sp = tuple.CreateStructuredArray();
447 EXPECT_EQ(tuple.GetSize(), array_sp->GetSize());
448 EXPECT_EQ(lldb::eStructuredDataTypeInteger,
449 array_sp->GetItemAtIndex(0)->GetType());
450 EXPECT_EQ(lldb::eStructuredDataTypeString,
451 array_sp->GetItemAtIndex(1)->GetType());
452}
453
454TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality) {
455 // Test that a dictionary which is built through the native
456 // Python API behaves correctly when wrapped by a PythonDictionary.
457 static const unsigned dict_entries = 2;
458 const char *key_0 = "Key 0";
459 int key_1 = 1;
460 const int value_0 = 0;
461 const char *value_1 = "Value 1";
462
463 PythonObject py_keys[dict_entries];
464 PythonObject py_values[dict_entries];
465
466 py_keys[0] = PythonString(key_0);
467 py_keys[1] = PythonInteger(key_1);
468 py_values[0] = PythonInteger(value_0);
469 py_values[1] = PythonString(value_1);
470
471 PyObject *py_dict = PyDict_New();
472 EXPECT_TRUE(PythonDictionary::Check(py_dict));
473 PythonDictionary dict(PyRefType::Owned, py_dict);
474
475 for (unsigned i = 0; i < dict_entries; ++i)
476 PyDict_SetItem(mp: py_dict, key: py_keys[i].get(), item: py_values[i].get());
477 EXPECT_EQ(dict.GetSize(), dict_entries);
478 EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
479
480 // Verify that the values match
481 PythonObject chk_value1 = dict.GetItemForKey(key: py_keys[0]);
482 PythonObject chk_value2 = dict.GetItemForKey(key: py_keys[1]);
483 EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
484 EXPECT_TRUE(PythonString::Check(chk_value2.get()));
485
486 PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
487 auto chkint = As<long long>(obj: chk_value1);
488
489 EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
490 EXPECT_EQ(value_1, chk_str.GetString());
491}
492
493TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation) {
494 // Test that manipulation of a dictionary behaves correctly when wrapped
495 // by a PythonDictionary.
496 static const unsigned dict_entries = 2;
497
498 const char *const key_0 = "Key 0";
499 const char *const key_1 = "Key 1";
500 const long value_0 = 1;
501 const char *const value_1 = "Value 1";
502
503 PythonString keys[dict_entries];
504 PythonObject values[dict_entries];
505
506 keys[0] = PythonString(key_0);
507 keys[1] = PythonString(key_1);
508 values[0] = PythonInteger(value_0);
509 values[1] = PythonString(value_1);
510
511 PythonDictionary dict(PyInitialValue::Empty);
512 for (int i = 0; i < 2; ++i)
513 dict.SetItemForKey(key: keys[i], value: values[i]);
514
515 EXPECT_EQ(dict_entries, dict.GetSize());
516 EXPECT_FALSE(dict.HasKey("not_in_dict"));
517 EXPECT_TRUE(dict.HasKey(key_0));
518 EXPECT_TRUE(dict.HasKey(key_1));
519
520 // Verify that the keys and values match
521 PythonObject chk_value1 = dict.GetItemForKey(key: keys[0]);
522 PythonObject chk_value2 = dict.GetItemForKey(key: keys[1]);
523 EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
524 EXPECT_TRUE(PythonString::Check(chk_value2.get()));
525
526 auto chkint = As<long long>(obj: chk_value1);
527 PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
528
529 EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
530 EXPECT_EQ(value_1, chk_str.GetString());
531}
532
533TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary) {
534 static const char *const string_key0 = "String Key 0";
535 static const char *const string_key1 = "String Key 1";
536
537 static const char *const string_value0 = "String Value 0";
538 static const long int_value1 = 7;
539
540 PythonDictionary dict(PyInitialValue::Empty);
541 dict.SetItemForKey(key: PythonString(string_key0), value: PythonString(string_value0));
542 dict.SetItemForKey(key: PythonString(string_key1), value: PythonInteger(int_value1));
543
544 auto dict_sp = dict.CreateStructuredDictionary();
545 EXPECT_EQ(2U, dict_sp->GetSize());
546
547 EXPECT_TRUE(dict_sp->HasKey(string_key0));
548 EXPECT_TRUE(dict_sp->HasKey(string_key1));
549
550 auto string_sp = dict_sp->GetValueForKey(key: string_key0)->GetAsString();
551 auto int_sp = dict_sp->GetValueForKey(key: string_key1)->GetAsUnsignedInteger();
552
553 EXPECT_EQ(string_value0, string_sp->GetValue());
554 EXPECT_EQ(int_value1, long(int_sp->GetValue()));
555}
556
557TEST_F(PythonDataObjectsTest, TestPythonCallableCheck) {
558 PythonObject sys_exc_info = m_sys_module.ResolveName(name: "exc_info");
559 PythonObject none(PyRefType::Borrowed, Py_None);
560
561 EXPECT_TRUE(PythonCallable::Check(sys_exc_info.get()));
562 EXPECT_FALSE(PythonCallable::Check(none.get()));
563}
564
565TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke) {
566 auto list = m_builtins_module.ResolveName(name: "list").AsType<PythonCallable>();
567 PythonInteger one(1);
568 PythonString two("two");
569 PythonTuple three = {one, two};
570
571 PythonTuple tuple_to_convert = {one, two, three};
572 PythonObject result = list({tuple_to_convert});
573
574 EXPECT_TRUE(PythonList::Check(result.get()));
575 auto list_result = result.AsType<PythonList>();
576 EXPECT_EQ(3U, list_result.GetSize());
577 EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get());
578 EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get());
579 EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get());
580}
581
582TEST_F(PythonDataObjectsTest, TestPythonFile) {
583 auto file = FileSystem::Instance().Open(file_spec: FileSpec(FileSystem::DEV_NULL),
584 options: File::eOpenOptionReadOnly);
585 ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
586 auto py_file = PythonFile::FromFile(file&: *file.get(), mode: "r");
587 ASSERT_THAT_EXPECTED(py_file, llvm::Succeeded());
588 EXPECT_TRUE(PythonFile::Check(py_file.get().get()));
589}
590
591TEST_F(PythonDataObjectsTest, TestObjectAttributes) {
592 PythonInteger py_int(42);
593 EXPECT_TRUE(py_int.HasAttribute("numerator"));
594 EXPECT_FALSE(py_int.HasAttribute("this_should_not_exist"));
595
596 auto numerator_attr = As<long long>(obj: py_int.GetAttributeValue(attribute: "numerator"));
597
598 EXPECT_THAT_EXPECTED(numerator_attr, llvm::HasValue(42));
599}
600
601TEST_F(PythonDataObjectsTest, TestExtractingUInt64ThroughStructuredData) {
602 // Make up a custom dictionary with "sys" pointing to the `sys` module.
603 const char *key_name = "addr";
604 const uint64_t value = 0xf000000000000000ull;
605 PythonDictionary python_dict(PyInitialValue::Empty);
606 PythonInteger python_ull_value(PyRefType::Owned,
607 PyLong_FromUnsignedLongLong(value));
608 python_dict.SetItemForKey(key: PythonString(key_name), value: python_ull_value);
609 StructuredData::ObjectSP structured_data_sp =
610 python_dict.CreateStructuredObject();
611 EXPECT_TRUE((bool)structured_data_sp);
612 if (structured_data_sp) {
613 StructuredData::Dictionary *structured_dict_ptr =
614 structured_data_sp->GetAsDictionary();
615 EXPECT_TRUE(structured_dict_ptr != nullptr);
616 if (structured_dict_ptr) {
617 StructuredData::ObjectSP structured_addr_value_sp =
618 structured_dict_ptr->GetValueForKey(key: key_name);
619 EXPECT_TRUE((bool)structured_addr_value_sp);
620 const uint64_t extracted_value =
621 structured_addr_value_sp->GetUnsignedIntegerValue(fail_value: 123);
622 EXPECT_TRUE(extracted_value == value);
623 }
624 }
625}
626
627TEST_F(PythonDataObjectsTest, TestCallable) {
628
629 PythonDictionary globals(PyInitialValue::Empty);
630 auto builtins = PythonModule::BuiltinsModule();
631 llvm::Error error = globals.SetItem(key: "__builtins__", value: builtins);
632 ASSERT_FALSE(error);
633
634 {
635 PyObject *o = PyRun_String("lambda x : x", Py_eval_input, globals.get(),
636 globals.get());
637 ASSERT_FALSE(o == NULL);
638 auto lambda = Take<PythonCallable>(obj: o);
639 auto arginfo = lambda.GetArgInfo();
640 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
641 EXPECT_EQ(arginfo.get().max_positional_args, 1u);
642 }
643
644 {
645 PyObject *o = PyRun_String("lambda x,y=0: x", Py_eval_input, globals.get(),
646 globals.get());
647 ASSERT_FALSE(o == NULL);
648 auto lambda = Take<PythonCallable>(obj: o);
649 auto arginfo = lambda.GetArgInfo();
650 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
651 EXPECT_EQ(arginfo.get().max_positional_args, 2u);
652 }
653
654 {
655 PyObject *o = PyRun_String("lambda x,y=0, **kw: x", Py_eval_input,
656 globals.get(), globals.get());
657 ASSERT_FALSE(o == NULL);
658 auto lambda = Take<PythonCallable>(obj: o);
659 auto arginfo = lambda.GetArgInfo();
660 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
661 EXPECT_EQ(arginfo.get().max_positional_args, 2u);
662 }
663
664 {
665 PyObject *o = PyRun_String("lambda x,y,*a: x", Py_eval_input, globals.get(),
666 globals.get());
667 ASSERT_FALSE(o == NULL);
668 auto lambda = Take<PythonCallable>(obj: o);
669 auto arginfo = lambda.GetArgInfo();
670 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
671 EXPECT_EQ(arginfo.get().max_positional_args,
672 PythonCallable::ArgInfo::UNBOUNDED);
673 }
674
675 {
676 PyObject *o = PyRun_String("lambda x,y,*a,**kw: x", Py_eval_input,
677 globals.get(), globals.get());
678 ASSERT_FALSE(o == NULL);
679 auto lambda = Take<PythonCallable>(obj: o);
680 auto arginfo = lambda.GetArgInfo();
681 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
682 EXPECT_EQ(arginfo.get().max_positional_args,
683 PythonCallable::ArgInfo::UNBOUNDED);
684 }
685
686 {
687 const char *script = R"(
688class Foo:
689 def bar(self, x):
690 return x
691 @classmethod
692 def classbar(cls, x):
693 return x
694 @staticmethod
695 def staticbar(x):
696 return x
697 def __call__(self, x):
698 return x
699obj = Foo()
700bar_bound = Foo().bar
701bar_class = Foo().classbar
702bar_static = Foo().staticbar
703bar_unbound = Foo.bar
704
705
706class OldStyle:
707 def __init__(self, one, two, three):
708 pass
709
710class NewStyle(object):
711 def __init__(self, one, two, three):
712 pass
713
714)";
715 PyObject *o =
716 PyRun_String(script, Py_file_input, globals.get(), globals.get());
717 ASSERT_FALSE(o == NULL);
718 Take<PythonObject>(obj: o);
719
720 auto bar_bound = As<PythonCallable>(obj: globals.GetItem(key: "bar_bound"));
721 ASSERT_THAT_EXPECTED(bar_bound, llvm::Succeeded());
722 auto arginfo = bar_bound.get().GetArgInfo();
723 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
724 EXPECT_EQ(arginfo.get().max_positional_args, 1u);
725
726 auto bar_unbound = As<PythonCallable>(obj: globals.GetItem(key: "bar_unbound"));
727 ASSERT_THAT_EXPECTED(bar_unbound, llvm::Succeeded());
728 arginfo = bar_unbound.get().GetArgInfo();
729 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
730 EXPECT_EQ(arginfo.get().max_positional_args, 2u);
731
732 auto bar_class = As<PythonCallable>(obj: globals.GetItem(key: "bar_class"));
733 ASSERT_THAT_EXPECTED(bar_class, llvm::Succeeded());
734 arginfo = bar_class.get().GetArgInfo();
735 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
736 EXPECT_EQ(arginfo.get().max_positional_args, 1u);
737
738 auto bar_static = As<PythonCallable>(obj: globals.GetItem(key: "bar_static"));
739 ASSERT_THAT_EXPECTED(bar_static, llvm::Succeeded());
740 arginfo = bar_static.get().GetArgInfo();
741 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
742 EXPECT_EQ(arginfo.get().max_positional_args, 1u);
743
744 auto obj = As<PythonCallable>(obj: globals.GetItem(key: "obj"));
745 ASSERT_THAT_EXPECTED(obj, llvm::Succeeded());
746 arginfo = obj.get().GetArgInfo();
747 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
748 EXPECT_EQ(arginfo.get().max_positional_args, 1u);
749
750 auto oldstyle = As<PythonCallable>(obj: globals.GetItem(key: "OldStyle"));
751 ASSERT_THAT_EXPECTED(oldstyle, llvm::Succeeded());
752 arginfo = oldstyle.get().GetArgInfo();
753 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
754 EXPECT_EQ(arginfo.get().max_positional_args, 3u);
755
756 auto newstyle = As<PythonCallable>(obj: globals.GetItem(key: "NewStyle"));
757 ASSERT_THAT_EXPECTED(newstyle, llvm::Succeeded());
758 arginfo = newstyle.get().GetArgInfo();
759 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
760 EXPECT_EQ(arginfo.get().max_positional_args, 3u);
761 }
762
763#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
764
765 // the old implementation of GetArgInfo just doesn't work on builtins.
766
767 {
768 auto builtins = PythonModule::BuiltinsModule();
769 auto hex = As<PythonCallable>(obj: builtins.GetAttribute(name: "hex"));
770 ASSERT_THAT_EXPECTED(hex, llvm::Succeeded());
771 auto arginfo = hex.get().GetArgInfo();
772 ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
773 EXPECT_EQ(arginfo.get().max_positional_args, 1u);
774 }
775
776#endif
777}
778
779TEST_F(PythonDataObjectsTest, TestScript) {
780
781 static const char script[] = R"(
782def factorial(n):
783 if n > 1:
784 return n * factorial(n-1)
785 else:
786 return 1;
787main = factorial
788)";
789
790 PythonScript factorial(script);
791
792 EXPECT_THAT_EXPECTED(As<long long>(factorial(5ll)), llvm::HasValue(120));
793}
794
795TEST_F(PythonDataObjectsTest, TestExceptions) {
796
797 static const char script[] = R"(
798def foo():
799 return bar()
800def bar():
801 return baz()
802def baz():
803 return 1 / 0
804main = foo
805)";
806
807 PythonScript foo(script);
808
809 EXPECT_THAT_EXPECTED(
810 foo(), llvm::Failed<PythonException>(testing::Property(
811 &PythonException::ReadBacktrace,
812 testing::AllOf(testing::ContainsRegex("line 3, in foo"),
813 testing::ContainsRegex("line 5, in bar"),
814 testing::ContainsRegex("line 7, in baz"),
815 testing::ContainsRegex("ZeroDivisionError")))));
816
817#if !((defined(_WIN32) || defined(_WIN64)) && \
818 (defined(__aarch64__) || defined(_M_ARM64)))
819
820 static const char script2[] = R"(
821class MyError(Exception):
822 def __str__(self):
823 return self.my_message
824
825def main():
826 raise MyError("lol")
827
828)";
829
830 PythonScript lol(script2);
831
832 EXPECT_THAT_EXPECTED(
833 lol(),
834 llvm::Failed<PythonException>(testing::Property(
835 &PythonException::ReadBacktrace,
836 testing::AnyOf(
837 testing::ContainsRegex("MyError: <exception str\\(\\) failed>"),
838 testing::ContainsRegex("unprintable MyError")))));
839
840#endif
841}
842
843TEST_F(PythonDataObjectsTest, TestRun) {
844
845 PythonDictionary globals(PyInitialValue::Empty);
846
847 auto x = As<long long>(obj: runStringOneLine(string: "40 + 2", globals, locals: globals));
848 ASSERT_THAT_EXPECTED(x, llvm::Succeeded());
849 EXPECT_EQ(x.get(), 42l);
850
851 Expected<PythonObject> r = runStringOneLine(string: "n = 42", globals, locals: globals);
852 ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
853 auto y = As<long long>(obj: globals.GetItem(key: "n"));
854 ASSERT_THAT_EXPECTED(y, llvm::Succeeded());
855 EXPECT_EQ(y.get(), 42l);
856
857 const char script[] = R"(
858def foobar():
859 return "foo" + "bar" + "baz"
860g = foobar()
861)";
862
863 r = runStringMultiLine(string: script, globals, locals: globals);
864 ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
865 auto g = As<std::string>(obj: globals.GetItem(key: "g"));
866 ASSERT_THAT_EXPECTED(g, llvm::HasValue("foobarbaz"));
867}
868

source code of lldb/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp