https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/214295
There were a few tests for `lldb.value` in TestValueAPI.py, but they only checked conversion to `int` and `__bool__`. The class has more operators. Some of the operators were never tested, because they currently fail. This is does the first step in that it adds tests. --- <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub> >From c458d56810c264262cc5462c4345a4023b88e491 Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Wed, 5 Aug 2026 18:49:05 +0200 Subject: [PATCH] [lldb] Add tests for `lldb.value` --- .../API/python_api/value/value_wrap/Makefile | 3 + .../value/value_wrap/TestValueAPIWrapper.py | 269 ++++++++++++++++++ .../API/python_api/value/value_wrap/main.c | 39 +++ 3 files changed, 311 insertions(+) create mode 100644 lldb/test/API/python_api/value/value_wrap/Makefile create mode 100644 lldb/test/API/python_api/value/value_wrap/TestValueAPIWrapper.py create mode 100644 lldb/test/API/python_api/value/value_wrap/main.c diff --git a/lldb/test/API/python_api/value/value_wrap/Makefile b/lldb/test/API/python_api/value/value_wrap/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/python_api/value/value_wrap/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/python_api/value/value_wrap/TestValueAPIWrapper.py b/lldb/test/API/python_api/value/value_wrap/TestValueAPIWrapper.py new file mode 100644 index 0000000000000..f4745ead57bba --- /dev/null +++ b/lldb/test/API/python_api/value/value_wrap/TestValueAPIWrapper.py @@ -0,0 +1,269 @@ +""" +Test the lldb.value wrapper. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ValueAPIWrapper(TestBase): + def test(self): + self.build() + + _, process, thread, _ = lldbutil.run_to_source_breakpoint( + self, "// break here", lldb.SBFileSpec("main.c") + ) + frame = thread.GetFrameAtIndex(0) + + # Get the variables and check __bool__. + u32_zero = lldb.value(frame.FindVariable("u32_zero")) + self.assertTrue(u32_zero) + u32_one = lldb.value(frame.FindVariable("u32_one")) + self.assertTrue(u32_one) + u32_two = lldb.value(frame.FindVariable("u32_two")) + self.assertTrue(u32_two) + u32_four = lldb.value(frame.FindVariable("u32_four")) + self.assertTrue(u32_four) + + i32_zero = lldb.value(frame.FindVariable("i32_zero")) + self.assertTrue(i32_zero) + i32_one = lldb.value(frame.FindVariable("i32_one")) + self.assertTrue(i32_one) + i32_two = lldb.value(frame.FindVariable("i32_two")) + self.assertTrue(i32_two) + + i32_minus_one = lldb.value(frame.FindVariable("i32_minus_one")) + self.assertTrue(i32_minus_one) + i32_minus_two = lldb.value(frame.FindVariable("i32_minus_two")) + self.assertTrue(i32_minus_two) + + cstr = lldb.value(frame.FindVariable("cstr")) + self.assertTrue(cstr) + + arr = lldb.value(frame.FindVariable("arr")) + self.assertTrue(arr) + arr_start = lldb.value(frame.FindVariable("arr_start")) + self.assertTrue(arr_start) + arr_second = lldb.value(frame.FindVariable("arr_second")) + self.assertTrue(arr_second) + + engine = lldb.value(frame.FindVariable("engine")) + self.assertTrue(engine) + my_car = lldb.value(frame.FindVariable("my_car")) + self.assertTrue(my_car) + + self.assertFalse(lldb.value(frame.FindVariable("this_does_not_exist"))) + + # Test __str__(). + self.assertEqual(str(u32_zero), "(uint32_t) u32_zero = 0") + self.assertEqual(str(u32_one), "(uint32_t) u32_one = 1") + + # Test __getitem__(key). + self.assertIsInstance(arr[0], lldb.value) + self.assertEqual(int(arr[0]), 1) + self.assertEqual(int(arr[1]), 2) + self.assertEqual(int(arr[u32_two]), 3) + self.assertEqual(int(arr[i32_two]), 3) + with self.assertRaisesRegex(IndexError, "^Index '1' is out of range$"): + my_car[1] + with self.assertRaisesRegex(TypeError, "^No array item of type <class 'str'>$"): + my_car["engine"] + + # Test __iter__(): + self.assertTrue(all(isinstance(v, lldb.value) for v in arr)) + self.assertEqual(list(int(v) for v in arr), [1, 2, 3, 4, 5, 6]) + + # Test __getattr__(): + self.assertIsInstance(my_car.doors, lldb.value) + self.assertEqual(int(my_car.doors), 3) + self.assertEqual(int(my_car.wheels), 4) + self.assertEqual(int(my_car.engine.kind), 1) + with self.assertRaisesRegex( + AttributeError, "^Attribute 'windows' is not defined$" + ): + my_car.windows + + # Test __add__(other). + self.assertEqual(u32_one + i32_one, 2) + self.assertEqual(u32_one + 1, 2) + self.assertEqual(u32_one + i32_minus_one, 0) + self.assertEqual(i32_minus_two + u32_one, -1) + # Pointers use byte addresses (u16 *arr_start). + self.assertEqual(arr_start + 2, arr[1].sbvalue.GetLoadAddress()) + + # Test __sub__(other). + self.assertEqual(u32_two - 1, 1) + self.assertEqual(i32_minus_one - 4, -5) + self.assertEqual(u32_one - 4, -3) + self.assertEqual(arr_second - 2, int(arr_start)) + + # Test __mul__(other). + self.assertEqual(u32_two * 3, 6) + self.assertEqual(i32_one * 5, 5) + self.assertEqual(i32_minus_one * 3, -3) + self.assertEqual(i32_minus_one * i32_minus_two, 2) + + # Test __floordiv__(other). + self.assertEqual(u32_two // 2, 1) + self.assertEqual(i32_minus_two // i32_one, -2) + + # Test __mod__(other). + self.assertEqual(u32_two % 2, 0) + self.assertEqual(i32_minus_two % u32_two, 0) + + # Test __divmod__(other). + # FIXME: Returns one number right now - should return a tuple. + # self.assertEqual(divmod(u32_four, 3), divmod(4, 3)) + # self.assertEqual(divmod(u32_four, i32_two), divmod(4, 2)) + + # Test __pow__(other). + self.assertEqual(u32_two**2, 4) + self.assertEqual(i32_two**u32_four, 16) + + # Test __lshift__(other). + self.assertEqual(u32_one << 2, 4) + self.assertEqual(i32_two << u32_four, 32) + + # Test __rshift__(other). + self.assertEqual(i32_two >> 1, 1) + self.assertEqual(u32_four >> i32_one, 2) + + # Test __and__(other). + self.assertEqual(my_car.doors & 2, 2) + self.assertEqual(my_car.doors & u32_one, 1) + + # Test __xor__(other). + self.assertEqual(my_car.doors ^ 0b101, 0b110) + self.assertEqual(my_car.doors ^ u32_one, 0b10) + + # Test __or__(other). + self.assertEqual(u32_one | 2, 3) + self.assertEqual(u32_four | u32_two, 6) + + # Test __truediv__(other). + self.assertEqual(u32_two / 2, 1.0) + self.assertEqual(my_car.doors / u32_two, 3 / 2) + + # Test __neg__(). + self.assertEqual(-i32_one, -1) + self.assertEqual(-i32_minus_two, 2) + + # Test __pos__(). + self.assertEqual(+i32_one, 1) + self.assertEqual(+i32_minus_two, -2) + + # Test __abs__(). + self.assertEqual(abs(i32_minus_one), 1) + self.assertEqual(abs(u32_two), 2) + + # Test __invert__(). + self.assertEqual(~i32_one, -2) + + # Test __complex__(). + self.assertEqual(complex(u32_one), complex(1, 0)) + + # Test __len__(). + self.assertEqual(len(u32_four), 0) + self.assertEqual(len(arr), 6) + self.assertEqual(len(my_car), 3) + + # Test __eq__(). + self.assertEqual(u32_two, i32_two) + self.assertEqual(u32_two, 2) + self.assertEqual(u32_two, "(uint32_t) u32_two = 2") + with self.assertRaisesRegex( + TypeError, "^Unknown type <class 'bool'>, No equality operation defined.$" + ): + _unused = u32_one == True + + # Test __ne__(). + self.assertNotEqual(u32_two, 1) + self.assertNotEqual(u32_two, i32_one) + self.assertNotEqual(u32_two, "2") + with self.assertRaisesRegex( + TypeError, "^Unknown type <class 'bool'>, No equality operation defined.$" + ): + _unused = u32_one != True + + # FIXME: Missing __index__ for oct(), hex(), etc. + + # Test in-place operators (__i...__(self, other)). + + kind = engine.kind + self.assertEqual(kind, 1) + self.assertIsInstance(kind, lldb.value) + + # Test __iadd__(other). + kind += 1 + self.assertEqual(kind, 2) + self.assertIsInstance(kind, int) + kind = engine.kind + self.assertEqual(kind, 2) + + # Test __isub__(other). + kind -= 1 + self.assertEqual(kind, 1) + self.assertIsInstance(kind, int) + kind = engine.kind + self.assertEqual(kind, 1) + + # Test __imul__(other). + kind *= 6 + self.assertEqual(kind, 6) + self.assertIsInstance(kind, int) + kind = engine.kind + self.assertEqual(kind, 6) + + # Test __itruediv__(other). + kind /= 2 + self.assertEqual(kind, 3) + self.assertIsInstance(kind, float) + kind = engine.kind + # Keeps its value, because we try to set "3.0". + # FIXME: Raise error here. + self.assertEqual(kind, 6) + + # Test __ifloordiv__(other). + # FIXME: Passes too many arguments to __floordiv__. + + # Test __imod__(other). + # FIXME: Passes too many arguments to __mod__. + + # Test __ipow__(other). + # FIXME: Passes too many arguments to __pow__. + + # Reset value + kind *= 0 + kind = engine.kind + kind += 1 + kind = engine.kind + self.assertEqual(kind, 1) + self.assertIsInstance(kind, lldb.value) + + # Test __ilshift__(other). + kind <<= 3 + self.assertEqual(kind, 8) + self.assertIsInstance(kind, int) + kind = engine.kind + self.assertEqual(kind, 8) + + # Test __irshift__(other). + kind >>= 1 + self.assertEqual(kind, 4) + self.assertIsInstance(kind, int) + kind = engine.kind + self.assertEqual(kind, 4) + + # Test __iand__(other). + # FIXME: Passes too many arguments to __and__. + + # Test __ixor__(other). + # FIXME: Passes too many arguments to __xor__. + + # Test __ior__(other). + # FIXME: Passes too many arguments to __or__. + + process.Continue() + self.assertEqual(process.GetState(), lldb.eStateExited) + self.assertEqual(process.GetExitStatus(), 4) # Last value of `engine.kind`. diff --git a/lldb/test/API/python_api/value/value_wrap/main.c b/lldb/test/API/python_api/value/value_wrap/main.c new file mode 100644 index 0000000000000..17054a2a43edf --- /dev/null +++ b/lldb/test/API/python_api/value/value_wrap/main.c @@ -0,0 +1,39 @@ +#include <stdint.h> + +struct Engine { + int kind; +}; + +struct Car { + int doors; + int wheels; + struct Engine *engine; +}; + +int main() { + uint32_t u32_zero = 0; + uint32_t u32_one = 1; + uint32_t u32_two = 2; + uint32_t u32_four = 4; + + int32_t i32_zero = 0; + int32_t i32_one = 1; + int32_t i32_two = 2; + + int32_t i32_minus_one = -1; + int32_t i32_minus_two = -2; + + const char *cstr = "This is a c string"; + uint16_t arr[] = {1, 2, 3, 4, 5, 6}; + uint16_t *arr_start = &arr[0]; + uint16_t *arr_second = &arr[1]; + + struct Engine engine = {.kind = 1}; + struct Car my_car = { + .doors = 3, + .wheels = 4, + .engine = &engine, + }; + + return my_car.engine->kind; // break here +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
