"""
Test lldb data formatter subsystem for std::span
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class LibcxxSpanDataFormatterTestCase(TestBase):
def findVariable(self, name):
var = self.frame().FindVariable(name)
self.assertTrue(var.IsValid())
return var
def check_size(self, var_name, size):
var = self.findVariable(var_name)
self.assertEqual(var.GetNumChildren(), size)
def check_numbers(self, var_name):
"""Helper to check that data formatter sees contents of std::span correctly"""
expectedSize = 5
self.check_size(var_name, expectedSize)
self.expect_expr(
var_name,
result_type=f"std::span<int, {expectedSize}>",
result_summary=f"size={expectedSize}",
result_children=[
ValueCheck(name="[0]", value="1"),
ValueCheck(name="[1]", value="12"),
ValueCheck(name="[2]", value="123"),
ValueCheck(name="[3]", value="1234"),
ValueCheck(name="[4]", value="12345"),
],
)
# check access-by-index
self.expect_var_path(f"{var_name}[0]", type="int", value="1")
self.expect_var_path(f"{var_name}[1]", type="int", value="12")
self.expect_var_path(f"{var_name}[2]", type="int", value="123")
self.expect_var_path(f"{var_name}[3]", type="int", value="1234")
self.expect_var_path(f"{var_name}[4]", type="int", value="12345")
@add_test_categories(["libc++"])
@skipIf(compiler="clang", compiler_version=["<", "11.0"])
def test_with_run_command(self):
"""Test that std::span variables are formatted correctly when printed."""
self.build()
(self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp", False)
)
lldbutil.continue_to_breakpoint(process, bkpt)
# std::span of std::array with extents known at compile-time
self.check_numbers("numbers_span")
# check access to synthetic children for static spans
self.runCmd(
'type summary add --summary-string "item 0 is ${var[0]}" -x "std::span<" span'
)
self.expect_expr(
"numbers_span",
result_type="std::span<int, 5>",
result_summary="item 0 is 1",
)
self.runCmd(
'type summary add --summary-string "item 0 is ${svar[0]}" -x "std::span<" span'
)
self.expect_expr(
"numbers_span",
result_type="std::span<int, 5>",
result_summary="item 0 is 1",
)
self.runCmd("type summary delete span")
# New span with strings
lldbutil.continue_to_breakpoint(process, bkpt)
expectedStringSpanChildren = [
ValueCheck(name="[0]", summary='"smart"'),
ValueCheck(name="[1]", summary='"!!!"'),
]
self.expect_var_path(
"strings_span", summary="size=2", children=expectedStringSpanChildren
)
# check access to synthetic children for dynamic spans
self.runCmd(
'type summary add --summary-string "item 0 is ${var[0]}" dynamic_string_span'
)
self.expect_var_path("strings_span", summary='item 0 is "smart"')
self.runCmd(
'type summary add --summary-string "item 0 is ${svar[0]}" dynamic_string_span'
)
self.expect_var_path("strings_span", summary='item 0 is "smart"')
self.runCmd("type summary delete dynamic_string_span")
# test summaries based on synthetic children
self.runCmd(
'type summary add --summary-string "span has ${svar%#} items" -e dynamic_string_span'
)
self.expect_var_path("strings_span", summary="span has 2 items")
self.expect_var_path(
"strings_span",
summary="span has 2 items",
children=expectedStringSpanChildren,
)
# check access-by-index
self.expect_var_path("strings_span[0]", summary='"smart"')
self.expect_var_path("strings_span[1]", summary='"!!!"')
# Newly inserted value not visible to span
lldbutil.continue_to_breakpoint(process, bkpt)
self.expect_expr(
"strings_span",
result_summary="span has 2 items",
result_children=expectedStringSpanChildren,
)
self.runCmd("type summary delete dynamic_string_span")
lldbutil.continue_to_breakpoint(process, bkpt)
# Empty spans
self.expect_expr(
"static_zero_span", result_type="std::span<int, 0>", result_summary="size=0"
)
self.check_size("static_zero_span", 0)
self.expect_expr("dynamic_zero_span", result_summary="size=0")
self.check_size("dynamic_zero_span", 0)
# Nested spans
self.expect_expr(
"nested",
result_summary="size=2",
result_children=[
ValueCheck(
name="[0]", summary="size=2", children=expectedStringSpanChildren
),
ValueCheck(
name="[1]", summary="size=2", children=expectedStringSpanChildren
),
],
)
self.check_size("nested", 2)
@add_test_categories(["libc++"])
@skipIf(compiler="clang", compiler_version=["<", "11.0"])
def test_ref_and_ptr(self):
"""Test that std::span is correctly formatted when passed by ref and ptr"""
self.build()
(self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Stop here to check by ref", lldb.SBFileSpec("main.cpp", False)
)
# The reference should display the same was as the value did
self.check_numbers("ref")
# The pointer should just show the right number of elements:
ptrAddr = self.findVariable("ptr").GetValue()
self.expect_expr(
"ptr", result_type="std::span<int, 5> *", result_summary=f"{ptrAddr} size=5"
)