[Lldb-commits] [lldb] dd0fdf8 - [lldb] Add support for checking children in expect_expr
Raphael Isemann via lldb-commits
lldb-commits at lists.llvm.org
Wed Aug 12 03:11:51 PDT 2020
Author: Raphael Isemann
Date: 2020-08-12T12:11:24+02:00
New Revision: dd0fdf80301e0b875d1898e01542c43b991e1b1c
URL: https://github.com/llvm/llvm-project/commit/dd0fdf80301e0b875d1898e01542c43b991e1b1c
DIFF: https://github.com/llvm/llvm-project/commit/dd0fdf80301e0b875d1898e01542c43b991e1b1c.diff
LOG: [lldb] Add support for checking children in expect_expr
expect_expr currently can't verify the children of the result SBValue.
This patch adds the ability to check them. The idea is to have a CheckValue
class where one can specify what attributes of a SBValue should be checked.
Beside the properties we already check for (summary, type, etc.) this also
has a list of children which is again just a list of CheckValue object (which
can also have children of their own).
The main motivation is to make checking the children no longer based
on error-prone substring checks that allow tests to pass just because
for example the error message contains the expected substrings by accident.
I also expect that we can just have a variant of `expect_expr` for LLDB's
expression paths (aka 'frame var') feature.
Reviewed By: labath
Differential Revision: https://reviews.llvm.org/D83792
Added:
Modified:
lldb/packages/Python/lldbsuite/test/lldbtest.py
lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py
lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/vector/TestDataFormatterLibcxxVector.py
Removed:
################################################################################
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index cc651e5b061d..ba1556794366 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -242,6 +242,77 @@ def which(program):
return exe_file
return None
+class ValueCheck:
+ def __init__(self, name=None, value=None, type=None, summary=None,
+ children=None):
+ """
+ :param name: The name that the SBValue should have. None if the summary
+ should not be checked.
+ :param summary: The summary that the SBValue should have. None if the
+ summary should not be checked.
+ :param value: The value that the SBValue should have. None if the value
+ should not be checked.
+ :param type: The type that the SBValue result should have. None if the
+ type should not be checked.
+ :param children: A list of ValueChecks that need to match the children
+ of this SBValue. None if children shouldn't be checked.
+ The order of checks is the order of the checks in the
+ list. The number of checks has to match the number of
+ children.
+ """
+ self.expect_name = name
+ self.expect_value = value
+ self.expect_type = type
+ self.expect_summary = summary
+ self.children = children
+
+ def check_value(self, test_base, val, error_msg=None):
+ """
+ Checks that the given value matches the currently set properties
+ of this ValueCheck. If a match failed, the given TestBase will
+ be used to emit an error. A custom error message can be specified
+ that will be used to describe failed check for this SBValue (but
+ not errors in the child values).
+ """
+
+ this_error_msg = error_msg if error_msg else ""
+ this_error_msg += "\nChecking SBValue: " + str(val)
+
+ test_base.assertSuccess(val.GetError())
+
+ if self.expect_name:
+ test_base.assertEqual(self.expect_name, val.GetName(),
+ this_error_msg)
+ if self.expect_value:
+ test_base.assertEqual(self.expect_value, val.GetValue(),
+ this_error_msg)
+ if self.expect_type:
+ test_base.assertEqual(self.expect_type, val.GetDisplayTypeName(),
+ this_error_msg)
+ if self.expect_summary:
+ test_base.assertEqual(self.expect_summary, val.GetSummary(),
+ this_error_msg)
+ if self.children is not None:
+ self.check_value_children(test_base, val, error_msg)
+
+ def check_value_children(self, test_base, val, error_msg=None):
+ """
+ Checks that the children of a SBValue match a certain structure and
+ have certain properties.
+
+ :param test_base: The current test's TestBase object.
+ :param val: The SBValue to check.
+ """
+
+ this_error_msg = error_msg if error_msg else ""
+ this_error_msg += "\nChecking SBValue: " + str(val)
+
+ test_base.assertEqual(len(self.children), val.GetNumChildren(), this_error_msg)
+
+ for i in range(0, val.GetNumChildren()):
+ expected_child = self.children[i]
+ actual_child = val.GetChildAtIndex(i)
+ expected_child.check_value(test_base, actual_child, error_msg)
class recording(SixStringIO):
"""
@@ -2424,6 +2495,7 @@ def expect_expr(
result_summary=None,
result_value=None,
result_type=None,
+ result_children=None
):
"""
Evaluates the given expression and verifies the result.
@@ -2431,6 +2503,8 @@ def expect_expr(
:param result_summary: The summary that the expression should have. None if the summary should not be checked.
:param result_value: The value that the expression should have. None if the value should not be checked.
:param result_type: The type that the expression result should have. None if the type should not be checked.
+ :param result_children: The expected children of the expression result
+ as a list of ValueChecks. None if the children shouldn't be checked.
"""
self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'")
@@ -2454,16 +2528,9 @@ def expect_expr(
target = self.dbg.GetDummyTarget()
eval_result = target.EvaluateExpression(expr, options)
- self.assertSuccess(eval_result.GetError())
-
- if result_type:
- self.assertEqual(result_type, eval_result.GetDisplayTypeName())
-
- if result_value:
- self.assertEqual(result_value, eval_result.GetValue())
-
- if result_summary:
- self.assertEqual(result_summary, eval_result.GetSummary())
+ value_check = ValueCheck(type=result_type, value=result_value,
+ summary=result_summary, children=result_children)
+ value_check.check_value(self, eval_result, str(eval_result))
def invoke(self, obj, name, trace=False):
"""Use reflection to call a method dynamically with no argument."""
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py
index bd7962f2f54d..87173c9aad42 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py
@@ -19,6 +19,11 @@ def setUp(self):
ns = 'ndk' if lldbplatformutil.target_is_android() else ''
self.namespace = 'std'
+ def check_pair(self, first_value, second_value):
+ pair_children = [ValueCheck(name="first", value=first_value),
+ ValueCheck(name="second", value=second_value)]
+ return ValueCheck(children=pair_children)
+
@add_test_categories(["libc++"])
def test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
@@ -51,10 +56,8 @@ def cleanup():
self.addTearDownHook(cleanup)
ns = self.namespace
- self.expect('p ii',
- substrs=['%s::map' % ns,
- 'size=0',
- '{}'])
+ self.expect_expr("ii", result_summary="size=0", result_children=[])
+
self.expect('frame var ii',
substrs=['%s::map' % ns,
'size=0',
@@ -62,14 +65,10 @@ def cleanup():
lldbutil.continue_to_breakpoint(self.process(), bkpt)
- self.expect('p ii',
- substrs=['%s::map' % ns, 'size=2',
- '[0] = ',
- 'first = 0',
- 'second = 0',
- '[1] = ',
- 'first = 1',
- 'second = 1'])
+ self.expect_expr("ii", result_summary="size=2", result_children=[
+ self.check_pair("0", "0"),
+ self.check_pair("1", "1")
+ ])
self.expect('frame variable ii',
substrs=['%s::map' % ns, 'size=2',
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/vector/TestDataFormatterLibcxxVector.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/vector/TestDataFormatterLibcxxVector.py
index 649c0fee4bd9..45dffdae269d 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/vector/TestDataFormatterLibcxxVector.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/vector/TestDataFormatterLibcxxVector.py
@@ -26,16 +26,15 @@ def check_numbers(self, var_name):
'[6] = 1234567',
'}'])
- self.expect("p " + var_name,
- substrs=['$', 'size=7',
- '[0] = 1',
- '[1] = 12',
- '[2] = 123',
- '[3] = 1234',
- '[4] = 12345',
- '[5] = 123456',
- '[6] = 1234567',
- '}'])
+ self.expect_expr(var_name, result_summary="size=7", result_children=[
+ ValueCheck(value="1"),
+ ValueCheck(value="12"),
+ ValueCheck(value="123"),
+ ValueCheck(value="1234"),
+ ValueCheck(value="12345"),
+ ValueCheck(value="123456"),
+ ValueCheck(value="1234567"),
+ ])
# check access-by-index
self.expect("frame variable " + var_name + "[0]",
More information about the lldb-commits
mailing list