Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 107 additions & 4 deletions lldb/bindings/interface/SBStructuredDataExtensions.i
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,119 @@ STRING_EXTENSION_OUTSIDE(SBStructuredData)
%extend lldb::SBStructuredData {
#ifdef SWIGPYTHON
%pythoncode%{
def __int__(self):
return self.GetSignedInteger()

def __len__(self):
'''Return the number of element in a lldb.SBStructuredData object.'''
return self.GetSize()

def __iter__(self):
'''Iterate over all the elements in a lldb.SBStructuredData object.'''
return lldb_iter(self, 'GetSize', 'GetItemAtIndex')
data_type = self.GetType()
if data_type == eStructuredDataTypeArray:
for i in range(self.GetSize()):
yield self.GetItemAtIndex(i).dynamic
return
elif data_type == eStructuredDataTypeDictionary:
keys = SBStringList()
self.GetKeys(keys)
return iter(keys)
else:
raise TypeError(f"cannot iterate {self.type_name(data_type)} type")

def __getitem__(self, key):
data_type = self.GetType()
if data_type == eStructuredDataTypeArray:
if not isinstance(key, int):
raise TypeError("subscript index must be an integer")
count = len(self)
if -count <= key < count:
key %= count
return self.GetItemAtIndex(key).dynamic
raise IndexError("index out of range")
elif data_type == eStructuredDataTypeDictionary:
if not isinstance(key, str):
raise TypeError("subscript key must be a string")
return self.GetValueForKey(key).dynamic
else:
raise TypeError(f"cannot subscript {self.type_name(data_type)} type")

def __str__(self):
data_type = self.GetType()
if data_type in (
eStructuredDataTypeString,
eStructuredDataTypeInteger,
eStructuredDataTypeSignedInteger,
eStructuredDataTypeFloat,
):
return str(self.dynamic)
else:
return repr(self)

def __int__(self):
data_type = self.GetType()
if data_type in (
eStructuredDataTypeInteger,
eStructuredDataTypeSignedInteger,
):
return self.dynamic
else:
raise TypeError(f"cannot convert {self.type_name(data_type)} to int")

def __float__(self):
data_type = self.GetType()
if data_type in (
eStructuredDataTypeFloat,
eStructuredDataTypeInteger,
eStructuredDataTypeSignedInteger,
):
return float(self.dynamic)
else:
raise TypeError(f"cannot convert {self.type_name(data_type)} to float")

@property
def dynamic(self):
data_type = self.GetType()
if data_type == eStructuredDataTypeNull:
return None
elif data_type == eStructuredDataTypeBoolean:
return self.GetBooleanValue()
elif data_type == eStructuredDataTypeInteger:
return self.GetUnsignedIntegerValue()
elif data_type == eStructuredDataTypeSignedInteger:
return self.GetSignedIntegerValue()
elif data_type == eStructuredDataTypeFloat:
return self.GetFloatValue()
elif data_type == eStructuredDataTypeString:
size = len(self) or 1023
return self.GetStringValue(size + 1)
elif data_type == eStructuredDataTypeGeneric:
return self.GetGenericValue()
else:
return self

@staticmethod
def type_name(t):
if t == eStructuredDataTypeNull:
return "null"
elif t == eStructuredDataTypeBoolean:
return "boolean"
elif t == eStructuredDataTypeInteger:
return "integer"
elif t == eStructuredDataTypeSignedInteger:
return "integer"
elif t == eStructuredDataTypeFloat:
return "float"
elif t == eStructuredDataTypeString:
return "string"
elif t == eStructuredDataTypeArray:
return "array"
elif t == eStructuredDataTypeDictionary:
return "dictionary"
elif t == eStructuredDataTypeGeneric:
return "generic"
elif t == eStructuredDataTypeInvalid:
return "invalid"
else:
raise TypeError(f"unknown structured data type: {t}")
%}
#endif
}
105 changes: 79 additions & 26 deletions lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ def structured_data_api_test(self):
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 = lldb.SBStructuredData()
dict_struct = example.GetValueForKey("key_dict")

# Tests for dictionary data type
Expand Down Expand Up @@ -113,18 +114,22 @@ class MyRandomClass:
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)
Expand Down Expand Up @@ -187,38 +192,35 @@ class MyRandomClass:
self.assertEqual(sb_data, example_arr)

def invalid_struct_test(self, example):
invalid_struct = lldb.SBStructuredData()
invalid_struct = example.GetValueForKey("invalid_key")
if invalid_struct.IsValid():
self.fail("An invalid object should have been returned")

# Check Type API
if not invalid_struct.GetType() == lldb.eStructuredDataTypeInvalid:
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 = lldb.SBStructuredData()
dict_struct = example.GetValueForKey("key_dict")
if not dict_struct.IsValid():
self.fail("A valid object should have been returned")

# Check Type API
if not dict_struct.GetType() == lldb.eStructuredDataTypeDictionary:
if dict_struct.GetType() != lldb.eStructuredDataTypeDictionary:
self.fail("Wrong type returned: " + str(dict_struct.GetType()))

# Check Size API for 'dictionary' type
if not dict_struct.GetSize() == 6:
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 = lldb.SBStructuredData()
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 not string_struct.GetType() == lldb.eStructuredDataTypeString:
if string_struct.GetType() != lldb.eStructuredDataTypeString:
self.fail("Wrong type returned: " + str(string_struct.GetType()))

# Check API returning 'string' value
Expand All @@ -238,18 +240,17 @@ 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 = lldb.SBStructuredData()
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 not uint_struct.GetType() == lldb.eStructuredDataTypeInteger:
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 not output == 0xFFFFFFFF00000000:
if output != 0xFFFFFFFF00000000:
self.fail("wrong output: " + str(output))

# Calling wrong API on a SBStructuredData
Expand All @@ -262,18 +263,17 @@ 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 = lldb.SBStructuredData()
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 not sint_struct.GetType() == lldb.eStructuredDataTypeSignedInteger:
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 not output == -42:
if output != -42:
self.fail("wrong output: " + str(output))

# Calling wrong API on a SBStructuredData
Expand All @@ -283,28 +283,26 @@ def sint_struct_test(self, dict_struct):
self.fail("Valid string " + output + " returned for an integer object")

def double_struct_test(self, dict_struct):
floating_point_struct = lldb.SBStructuredData()
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 not floating_point_struct.GetType() == lldb.eStructuredDataTypeFloat:
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 not output == 2.99:
if output != 2.99:
self.fail("wrong output: " + str(output))

def bool_struct_test(self, dict_struct):
bool_struct = lldb.SBStructuredData()
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 not bool_struct.GetType() == lldb.eStructuredDataTypeBoolean:
if bool_struct.GetType() != lldb.eStructuredDataTypeBoolean:
self.fail("Wrong type returned: " + str(bool_struct.GetType()))

# Check API returning 'bool' value
Expand All @@ -314,35 +312,90 @@ def bool_struct_test(self, dict_struct):

def array_struct_test(self, dict_struct):
# Check API returning a valid SBStructuredData of 'array' type
array_struct = lldb.SBStructuredData()
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 not array_struct.GetType() == lldb.eStructuredDataTypeArray:
if array_struct.GetType() != lldb.eStructuredDataTypeArray:
self.fail("Wrong type returned: " + str(array_struct.GetType()))

# Check Size API for 'array' type
if not array_struct.GetSize() == 2:
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 not string_struct.GetType() == lldb.eStructuredDataTypeString:
if string_struct.GetType() != lldb.eStructuredDataTypeString:
self.fail("Wrong type returned: " + str(string_struct.GetType()))
output = string_struct.GetStringValue(5)
if not output == "23":
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 not string_struct.GetType() == lldb.eStructuredDataTypeString:
if string_struct.GetType() != lldb.eStructuredDataTypeString:
self.fail("Wrong type returned: " + str(string_struct.GetType()))
output = string_struct.GetStringValue(5)
if not output == "arr":
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])