1""" 2Test lldb data formatter subsystem for std::span 3""" 4 5import lldb 6from lldbsuite.test.decorators import * 7from lldbsuite.test.lldbtest import * 8from lldbsuite.test import lldbutil 9 10class LibcxxSpanDataFormatterTestCase(TestBase): 11 12 def findVariable(self, name): 13 var = self.frame().FindVariable(name) 14 self.assertTrue(var.IsValid()) 15 return var 16 17 def check_size(self, var_name, size): 18 var = self.findVariable(var_name) 19 self.assertEqual(var.GetNumChildren(), size) 20 21 def check_numbers(self, var_name): 22 """Helper to check that data formatter sees contents of std::span correctly""" 23 24 expectedSize = 5 25 self.check_size(var_name, expectedSize) 26 27 self.expect_expr( 28 var_name, result_type=f'std::span<int, {expectedSize}>', 29 result_summary=f'size={expectedSize}', 30 result_children=[ 31 ValueCheck(name='[0]', value='1'), 32 ValueCheck(name='[1]', value='12'), 33 ValueCheck(name='[2]', value='123'), 34 ValueCheck(name='[3]', value='1234'), 35 ValueCheck(name='[4]', value='12345') 36 ]) 37 38 # check access-by-index 39 self.expect_var_path(f'{var_name}[0]', type='int', value='1') 40 self.expect_var_path(f'{var_name}[1]', type='int', value='12') 41 self.expect_var_path(f'{var_name}[2]', type='int', value='123') 42 self.expect_var_path(f'{var_name}[3]', type='int', value='1234') 43 self.expect_var_path(f'{var_name}[4]', type='int', value='12345') 44 45 @add_test_categories(['libc++']) 46 @skipIf(compiler='clang', compiler_version=['<', '11.0']) 47 def test_with_run_command(self): 48 """Test that std::span variables are formatted correctly when printed.""" 49 self.build() 50 (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 51 self, 'break here', lldb.SBFileSpec('main.cpp', False)) 52 53 lldbutil.continue_to_breakpoint(process, bkpt) 54 55 # std::span of std::array with extents known at compile-time 56 self.check_numbers('numbers_span') 57 58 # check access to synthetic children for static spans 59 self.runCmd('type summary add --summary-string "item 0 is ${var[0]}" -x "std::span<" span') 60 self.expect_expr('numbers_span', 61 result_type='std::span<int, 5>', 62 result_summary='item 0 is 1') 63 64 self.runCmd('type summary add --summary-string "item 0 is ${svar[0]}" -x "std::span<" span') 65 self.expect_expr('numbers_span', 66 result_type='std::span<int, 5>', 67 result_summary='item 0 is 1') 68 69 self.runCmd('type summary delete span') 70 71 # New span with strings 72 lldbutil.continue_to_breakpoint(process, bkpt) 73 74 expectedStringSpanChildren = [ ValueCheck(name='[0]', summary='"smart"'), 75 ValueCheck(name='[1]', summary='"!!!"') ] 76 77 self.expect_var_path('strings_span', 78 summary='size=2', 79 children=expectedStringSpanChildren) 80 81 # check access to synthetic children for dynamic spans 82 self.runCmd('type summary add --summary-string "item 0 is ${var[0]}" dynamic_string_span') 83 self.expect_var_path('strings_span', summary='item 0 is "smart"') 84 85 self.runCmd('type summary add --summary-string "item 0 is ${svar[0]}" dynamic_string_span') 86 self.expect_var_path('strings_span', summary='item 0 is "smart"') 87 88 self.runCmd('type summary delete dynamic_string_span') 89 90 # test summaries based on synthetic children 91 self.runCmd( 92 'type summary add --summary-string "span has ${svar%#} items" -e dynamic_string_span') 93 94 self.expect_var_path('strings_span', summary='span has 2 items') 95 96 self.expect_var_path('strings_span', 97 summary='span has 2 items', 98 children=expectedStringSpanChildren) 99 100 # check access-by-index 101 self.expect_var_path('strings_span[0]', summary='"smart"'); 102 self.expect_var_path('strings_span[1]', summary='"!!!"'); 103 104 # Newly inserted value not visible to span 105 lldbutil.continue_to_breakpoint(process, bkpt) 106 107 self.expect_expr('strings_span', 108 result_summary='span has 2 items', 109 result_children=expectedStringSpanChildren) 110 111 self.runCmd('type summary delete dynamic_string_span') 112 113 lldbutil.continue_to_breakpoint(process, bkpt) 114 115 # Empty spans 116 self.expect_expr('static_zero_span', 117 result_type='std::span<int, 0>', 118 result_summary='size=0') 119 self.check_size('static_zero_span', 0) 120 121 self.expect_expr('dynamic_zero_span', 122 result_summary='size=0') 123 self.check_size('dynamic_zero_span', 0) 124 125 # Nested spans 126 self.expect_expr('nested', 127 result_summary='size=2', 128 result_children=[ 129 ValueCheck(name='[0]', summary='size=2', 130 children=expectedStringSpanChildren), 131 ValueCheck(name='[1]', summary='size=2', 132 children=expectedStringSpanChildren) 133 ]) 134 self.check_size('nested', 2) 135 136 @add_test_categories(['libc++']) 137 @skipIf(compiler='clang', compiler_version=['<', '11.0']) 138 def test_ref_and_ptr(self): 139 """Test that std::span is correctly formatted when passed by ref and ptr""" 140 self.build() 141 (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 142 self, 'Stop here to check by ref', lldb.SBFileSpec('main.cpp', False)) 143 144 # The reference should display the same was as the value did 145 self.check_numbers('ref') 146 147 # The pointer should just show the right number of elements: 148 149 ptrAddr = self.findVariable('ptr').GetValue() 150 self.expect_expr('ptr', result_type='std::span<int, 5> *', 151 result_summary=f'{ptrAddr} size=5') 152