mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
* Adds `dynamic` property to automatically convert `SBStructuredData`
instances to the associated Python type (`str`, `int`, `float`, `bool`,
`NoneType`, etc)
* Implements `__getitem__` for Pythonic array and dictionary
subscripting
* Subscripting return the result of the `dynamic` property
* Updates `__iter__` to support dictionary instances (supporting `for`
loops)
* Adds `__str__`, `__int__`, and `__float__`
With these changes, these two expressions are equal:
```py
data["name"] == data.GetValueForKey("name").GetStringValue(1024)
```
**Note**: Unlike the original commit (#155061), this re-commit removes
the `__bool__` implementation, which broke crashlog. Somewhere in the
crashlog execution, it depends on `__bool__` meaning only `IsValid()`.
Additionally did some cleanup in TestStructuredDataAPI.py.
402 lines
15 KiB
Python
402 lines
15 KiB
Python
"""
|
|
Test some SBStructuredData API.
|
|
"""
|
|
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
import json
|
|
|
|
class TestStructuredDataAPI(TestBase):
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
def test(self):
|
|
self.structured_data_api_test()
|
|
|
|
def structured_data_api_test(self):
|
|
error = lldb.SBError()
|
|
s = lldb.SBStream()
|
|
|
|
dict_str = json.dumps(
|
|
{
|
|
"key_dict": {
|
|
"key_string": "STRING",
|
|
"key_uint": 0xFFFFFFFF00000000,
|
|
"key_sint": -42,
|
|
"key_float": 2.99,
|
|
"key_bool": True,
|
|
"key_array": ["23", "arr"],
|
|
}
|
|
}
|
|
)
|
|
s.Print(dict_str)
|
|
example = lldb.SBStructuredData()
|
|
|
|
# Check SetFromJSON API for dictionaries, integers, floating point
|
|
# values, strings and arrays
|
|
error = example.SetFromJSON(s)
|
|
if not error.Success():
|
|
self.fail("FAILED: " + error.GetCString())
|
|
|
|
# Tests for invalid data type
|
|
self.invalid_struct_test(example)
|
|
|
|
# Test that GetDescription works:
|
|
s.Clear()
|
|
error = example.GetDescription(s)
|
|
self.assertSuccess(error, "GetDescription works")
|
|
# Ensure str() doesn't raise an exception.
|
|
self.assertTrue(str(example))
|
|
if not "key_float" in s.GetData():
|
|
self.fail("FAILED: could not find key_float in description output")
|
|
|
|
dict_struct = example.GetValueForKey("key_dict")
|
|
|
|
# Tests for dictionary data type
|
|
self.dictionary_struct_test(example)
|
|
|
|
# Tests for string data type
|
|
self.string_struct_test(dict_struct)
|
|
|
|
# Tests for integer data type
|
|
self.uint_struct_test(dict_struct)
|
|
|
|
# Tests for integer data type
|
|
self.sint_struct_test(dict_struct)
|
|
|
|
# Tests for floating point data type
|
|
self.double_struct_test(dict_struct)
|
|
|
|
# Tests for boolean data type
|
|
self.bool_struct_test(dict_struct)
|
|
|
|
# Tests for array data type
|
|
self.array_struct_test(dict_struct)
|
|
|
|
s.Clear()
|
|
self.assertSuccess(example.GetAsJSON(s))
|
|
py_obj = json.loads(s.GetData())
|
|
self.assertTrue(py_obj)
|
|
self.assertIn("key_dict", py_obj)
|
|
|
|
py_dict = py_obj["key_dict"]
|
|
self.assertEqual(py_dict["key_string"], "STRING")
|
|
self.assertEqual(py_dict["key_uint"], 0xFFFFFFFF00000000)
|
|
self.assertEqual(py_dict["key_sint"], -42)
|
|
self.assertEqual(py_dict["key_float"], 2.99)
|
|
self.assertEqual(py_dict["key_bool"], True)
|
|
self.assertEqual(py_dict["key_array"], ["23", "arr"])
|
|
|
|
class MyRandomClass:
|
|
payload = "foo"
|
|
|
|
py_dict["key_generic"] = MyRandomClass()
|
|
|
|
stp = lldb.SBScriptObject(py_dict, lldb.eScriptLanguagePython)
|
|
self.assertEqual(stp.ptr, py_dict)
|
|
|
|
sd = lldb.SBStructuredData(stp, self.dbg)
|
|
self.assertTrue(sd.IsValid())
|
|
self.assertEqual(sd.GetSize(), len(py_dict))
|
|
|
|
generic_sd = sd.GetValueForKey("key_generic")
|
|
self.assertTrue(generic_sd.IsValid())
|
|
self.assertEqual(generic_sd.GetType(), lldb.eStructuredDataTypeGeneric)
|
|
|
|
my_random_class = generic_sd.GetGenericValue()
|
|
self.assertTrue(my_random_class)
|
|
self.assertEqual(my_random_class.payload, MyRandomClass.payload)
|
|
|
|
example = lldb.SBStructuredData()
|
|
self.assertSuccess(example.SetFromJSON("1"))
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeInteger)
|
|
self.assertEqual(example.GetIntegerValue(), 1)
|
|
self.assertEqual(int(example), 1)
|
|
|
|
self.assertSuccess(example.SetFromJSON("4.19"))
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeFloat)
|
|
self.assertEqual(example.GetFloatValue(), 4.19)
|
|
self.assertEqual(float(example), 4.19)
|
|
|
|
self.assertSuccess(example.SetFromJSON('"Bonjour, 123!"'))
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeString)
|
|
self.assertEqual(example.GetStringValue(42), "Bonjour, 123!")
|
|
self.assertEqual(str(example), "Bonjour, 123!")
|
|
|
|
self.assertSuccess(example.SetFromJSON("true"))
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeBoolean)
|
|
self.assertTrue(example.GetBooleanValue())
|
|
self.assertTrue(example)
|
|
|
|
self.assertSuccess(example.SetFromJSON("null"))
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeNull)
|
|
|
|
example = lldb.SBStructuredData()
|
|
example.SetUnsignedIntegerValue(1)
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeInteger)
|
|
self.assertEqual(example.GetIntegerValue(), 1)
|
|
|
|
example.SetSignedIntegerValue(-42)
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeSignedInteger)
|
|
self.assertEqual(example.GetSignedIntegerValue(), -42)
|
|
|
|
example.SetFloatValue(4.19)
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeFloat)
|
|
self.assertEqual(example.GetFloatValue(), 4.19)
|
|
|
|
example.SetStringValue("Bonjour, 123!")
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeString)
|
|
self.assertEqual(example.GetStringValue(42), "Bonjour, 123!")
|
|
|
|
value = lldb.SBStructuredData()
|
|
example.SetValueForKey("Hello", value)
|
|
self.assertEqual(example.GetSize(), 0)
|
|
|
|
nested_obj = lldb.SBStructuredData()
|
|
nested_obj.SetStringValue("World")
|
|
example.SetValueForKey("Hello", nested_obj)
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeDictionary)
|
|
nested_obj = None
|
|
nested_obj = example.GetValueForKey("Hello")
|
|
self.assertTrue(nested_obj.IsValid())
|
|
self.assertEqual(nested_obj.GetType(), lldb.eStructuredDataTypeString)
|
|
self.assertEqual(nested_obj.GetStringValue(42), "World")
|
|
|
|
example.SetBooleanValue(True)
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeBoolean)
|
|
self.assertTrue(example.GetBooleanValue())
|
|
|
|
rnd_obj = MyRandomClass()
|
|
stp = lldb.SBScriptObject(rnd_obj, lldb.eScriptLanguagePython)
|
|
self.assertEqual(stp.ptr, rnd_obj)
|
|
|
|
example.SetGenericValue(stp)
|
|
self.assertEqual(example.GetType(), lldb.eStructuredDataTypeGeneric)
|
|
|
|
my_random_class = example.GetGenericValue()
|
|
self.assertTrue(my_random_class)
|
|
self.assertEqual(my_random_class.payload, MyRandomClass.payload)
|
|
|
|
example_arr = [1, 2.3, "4", {"5": False}]
|
|
arr_str = json.dumps(example_arr)
|
|
s.Clear()
|
|
s.Print(arr_str)
|
|
self.assertSuccess(example.SetFromJSON(s))
|
|
|
|
s.Clear()
|
|
self.assertSuccess(example.GetAsJSON(s))
|
|
sb_data = json.loads(s.GetData())
|
|
self.assertEqual(sb_data, example_arr)
|
|
|
|
def invalid_struct_test(self, example):
|
|
invalid_struct = example.GetValueForKey("invalid_key")
|
|
if invalid_struct.IsValid():
|
|
self.fail("An invalid object should have been returned")
|
|
|
|
# Check Type API
|
|
if invalid_struct.GetType() != lldb.eStructuredDataTypeInvalid:
|
|
self.fail("Wrong type returned: " + str(invalid_struct.GetType()))
|
|
|
|
def dictionary_struct_test(self, example):
|
|
# Check API returning a valid SBStructuredData of 'dictionary' type
|
|
dict_struct = example.GetValueForKey("key_dict")
|
|
if not dict_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
|
|
# Check Type API
|
|
if dict_struct.GetType() != lldb.eStructuredDataTypeDictionary:
|
|
self.fail("Wrong type returned: " + str(dict_struct.GetType()))
|
|
|
|
# Check Size API for 'dictionary' type
|
|
if dict_struct.GetSize() != 6:
|
|
self.fail("Wrong no of elements returned: " + str(dict_struct.GetSize()))
|
|
|
|
def string_struct_test(self, dict_struct):
|
|
string_struct = dict_struct.GetValueForKey("key_string")
|
|
if not string_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
|
|
# Check Type API
|
|
if string_struct.GetType() != lldb.eStructuredDataTypeString:
|
|
self.fail("Wrong type returned: " + str(string_struct.GetType()))
|
|
|
|
# Check API returning 'string' value
|
|
output = string_struct.GetStringValue(25)
|
|
if not "STRING" in output:
|
|
self.fail("wrong output: " + output)
|
|
|
|
# Calling wrong API on a SBStructuredData
|
|
# (e.g. getting an integer from a string type structure)
|
|
output = string_struct.GetIntegerValue()
|
|
if output:
|
|
self.fail(
|
|
"Valid integer value " + str(output) + " returned for a string object"
|
|
)
|
|
|
|
def uint_struct_test(self, dict_struct):
|
|
# Check a valid SBStructuredData containing an unsigned integer.
|
|
# We intentionally make this larger than what an int64_t can hold but
|
|
# still small enough to fit a uint64_t
|
|
uint_struct = dict_struct.GetValueForKey("key_uint")
|
|
if not uint_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
|
|
# Check Type API
|
|
if uint_struct.GetType() != lldb.eStructuredDataTypeInteger:
|
|
self.fail("Wrong type returned: " + str(uint_struct.GetType()))
|
|
|
|
# Check API returning unsigned integer value
|
|
output = uint_struct.GetUnsignedIntegerValue()
|
|
if output != 0xFFFFFFFF00000000:
|
|
self.fail("wrong output: " + str(output))
|
|
|
|
# Calling wrong API on a SBStructuredData
|
|
# (e.g. getting a string value from an integer type structure)
|
|
output = uint_struct.GetStringValue(25)
|
|
if output:
|
|
self.fail("Valid string " + output + " returned for an integer object")
|
|
|
|
def sint_struct_test(self, dict_struct):
|
|
# Check a valid SBStructuredData containing an signed integer.
|
|
# We intentionally make this smaller than what an uint64_t can hold but
|
|
# still small enough to fit a int64_t
|
|
sint_struct = dict_struct.GetValueForKey("key_sint")
|
|
if not sint_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
|
|
# Check Type API
|
|
if sint_struct.GetType() != lldb.eStructuredDataTypeSignedInteger:
|
|
self.fail("Wrong type returned: " + str(sint_struct.GetType()))
|
|
|
|
# Check API returning signed integer value
|
|
output = sint_struct.GetSignedIntegerValue()
|
|
if output != -42:
|
|
self.fail("wrong output: " + str(output))
|
|
|
|
# Calling wrong API on a SBStructuredData
|
|
# (e.g. getting a string value from an integer type structure)
|
|
output = sint_struct.GetStringValue(69)
|
|
if output:
|
|
self.fail("Valid string " + output + " returned for an integer object")
|
|
|
|
def double_struct_test(self, dict_struct):
|
|
floating_point_struct = dict_struct.GetValueForKey("key_float")
|
|
if not floating_point_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
|
|
# Check Type API
|
|
if floating_point_struct.GetType() != lldb.eStructuredDataTypeFloat:
|
|
self.fail("Wrong type returned: " + str(floating_point_struct.GetType()))
|
|
|
|
# Check API returning 'double' value
|
|
output = floating_point_struct.GetFloatValue()
|
|
if output != 2.99:
|
|
self.fail("wrong output: " + str(output))
|
|
|
|
def bool_struct_test(self, dict_struct):
|
|
bool_struct = dict_struct.GetValueForKey("key_bool")
|
|
if not bool_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
|
|
# Check Type API
|
|
if bool_struct.GetType() != lldb.eStructuredDataTypeBoolean:
|
|
self.fail("Wrong type returned: " + str(bool_struct.GetType()))
|
|
|
|
# Check API returning 'bool' value
|
|
output = bool_struct.GetBooleanValue()
|
|
if not output:
|
|
self.fail("wrong output: " + str(output))
|
|
|
|
def array_struct_test(self, dict_struct):
|
|
# Check API returning a valid SBStructuredData of 'array' type
|
|
array_struct = dict_struct.GetValueForKey("key_array")
|
|
if not array_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
|
|
# Check Type API
|
|
if array_struct.GetType() != lldb.eStructuredDataTypeArray:
|
|
self.fail("Wrong type returned: " + str(array_struct.GetType()))
|
|
|
|
# Check Size API for 'array' type
|
|
if array_struct.GetSize() != 2:
|
|
self.fail("Wrong no of elements returned: " + str(array_struct.GetSize()))
|
|
|
|
# Check API returning a valid SBStructuredData for different 'array'
|
|
# indices
|
|
string_struct = array_struct.GetItemAtIndex(0)
|
|
if not string_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
if string_struct.GetType() != lldb.eStructuredDataTypeString:
|
|
self.fail("Wrong type returned: " + str(string_struct.GetType()))
|
|
output = string_struct.GetStringValue(5)
|
|
if output != "23":
|
|
self.fail("wrong output: " + str(output))
|
|
|
|
string_struct = array_struct.GetItemAtIndex(1)
|
|
if not string_struct.IsValid():
|
|
self.fail("A valid object should have been returned")
|
|
if string_struct.GetType() != lldb.eStructuredDataTypeString:
|
|
self.fail("Wrong type returned: " + str(string_struct.GetType()))
|
|
output = string_struct.GetStringValue(5)
|
|
if output != "arr":
|
|
self.fail("wrong output: " + str(output))
|
|
|
|
def test_round_trip_scalars(self):
|
|
for original in (0, 11, -1, 0.0, 4.5, -0.25):
|
|
constructor = type(original)
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(original))
|
|
round_tripped = constructor(data)
|
|
self.assertEqual(round_tripped, original)
|
|
|
|
def test_dynamic(self):
|
|
for original in (0, 11, -1, 0.0, 4.5, -0.25, "", "dirk", True, False):
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(original))
|
|
self.assertEqual(data.dynamic, original)
|
|
|
|
def test_round_trip_int(self):
|
|
for original in (0, 11, -1):
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(original))
|
|
self.assertEqual(int(data), int(original))
|
|
|
|
def test_round_trip_float(self):
|
|
for original in (0, 11, -1, 0.0, 4.5, -0.25):
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(original))
|
|
self.assertEqual(float(data), float(original))
|
|
|
|
def test_iterate_array(self):
|
|
array = [0, 1, 2]
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(array))
|
|
for value in data:
|
|
self.assertEqual(value, array.pop(0))
|
|
|
|
def test_iterate_dictionary(self):
|
|
dictionary = {"0": 0, "1": 1, "2": 2}
|
|
keys = set(dictionary.keys())
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(dictionary))
|
|
for key in data:
|
|
self.assertIn(key, keys)
|
|
keys.remove(key)
|
|
|
|
def test_getitem_array(self):
|
|
array = [1, 2, 3]
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(array))
|
|
for i in range(len(array)):
|
|
self.assertEqual(data[i], array[i])
|
|
|
|
def test_getitem_dictionary(self):
|
|
dictionary = {"one": 1, "two": 2, "three": 3}
|
|
data = lldb.SBStructuredData()
|
|
data.SetFromJSON(json.dumps(dictionary))
|
|
for key in dictionary:
|
|
self.assertEqual(data[key], dictionary[key])
|