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

Reply via email to