github.com/kubeshark/ebpf@v0.9.2/btf/format_test.go (about) 1 package btf 2 3 import ( 4 "errors" 5 "fmt" 6 "go/format" 7 "strings" 8 "testing" 9 ) 10 11 func TestGoTypeDeclaration(t *testing.T) { 12 tests := []struct { 13 typ Type 14 output string 15 }{ 16 {&Int{Size: 1}, "type t uint8"}, 17 {&Int{Size: 1, Encoding: Bool}, "type t bool"}, 18 {&Int{Size: 2, Encoding: Bool}, "type t uint16"}, 19 {&Int{Size: 1, Encoding: Char}, "type t uint8"}, 20 {&Int{Size: 1, Encoding: Char | Signed}, "type t int8"}, 21 {&Int{Size: 2, Encoding: Char}, "type t uint16"}, 22 {&Int{Size: 2, Encoding: Signed}, "type t int16"}, 23 {&Int{Size: 4, Encoding: Signed}, "type t int32"}, 24 {&Int{Size: 8}, "type t uint64"}, 25 {&Typedef{Name: "frob", Type: &Int{Size: 8}}, "type t uint64"}, 26 {&Int{Size: 16}, "type t uint128"}, 27 {&Enum{Values: []EnumValue{{"FOO", 32}}, Size: 4}, "type t int32; const ( tFOO t = 32; )"}, 28 {&Enum{Values: []EnumValue{{"BAR", 1}}, Size: 1}, "type t int8; const ( tBAR t = 1; )"}, 29 {&Array{Nelems: 2, Type: &Int{Size: 1}}, "type t [2]uint8"}, 30 { 31 &Union{ 32 Size: 8, 33 Members: []Member{ 34 {Name: "a", Type: &Int{Size: 4}}, 35 {Name: "b", Type: &Int{Size: 8}}, 36 }, 37 }, 38 "type t struct { a uint32; _ [4]byte; }", 39 }, 40 { 41 &Struct{ 42 Name: "field padding", 43 Size: 16, 44 Members: []Member{ 45 {Name: "frob", Type: &Int{Size: 4}, Offset: 0}, 46 {Name: "foo", Type: &Int{Size: 8}, Offset: 8 * 8}, 47 }, 48 }, 49 "type t struct { frob uint32; _ [4]byte; foo uint64; }", 50 }, 51 { 52 &Struct{ 53 Name: "end padding", 54 Size: 16, 55 Members: []Member{ 56 {Name: "foo", Type: &Int{Size: 8}, Offset: 0}, 57 {Name: "frob", Type: &Int{Size: 4}, Offset: 8 * 8}, 58 }, 59 }, 60 "type t struct { foo uint64; frob uint32; _ [4]byte; }", 61 }, 62 { 63 &Struct{ 64 Name: "bitfield", 65 Size: 8, 66 Members: []Member{ 67 {Name: "foo", Type: &Int{Size: 4}, Offset: 0, BitfieldSize: 1}, 68 {Name: "frob", Type: &Int{Size: 4}, Offset: 4 * 8}, 69 }, 70 }, 71 "type t struct { _ [4]byte /* unsupported bitfield */; frob uint32; }", 72 }, 73 { 74 &Struct{ 75 Name: "nested", 76 Size: 8, 77 Members: []Member{ 78 { 79 Name: "foo", 80 Type: &Struct{ 81 Size: 4, 82 Members: []Member{ 83 {Name: "bar", Type: &Int{Size: 4}, Offset: 0}, 84 }, 85 }, 86 }, 87 {Name: "frob", Type: &Int{Size: 4}, Offset: 4 * 8}, 88 }, 89 }, 90 "type t struct { foo struct { bar uint32; }; frob uint32; }", 91 }, 92 { 93 &Struct{ 94 Name: "nested anon union", 95 Size: 8, 96 Members: []Member{ 97 { 98 Name: "", 99 Type: &Union{ 100 Size: 4, 101 Members: []Member{ 102 {Name: "foo", Type: &Int{Size: 4}, Offset: 0}, 103 {Name: "bar", Type: &Int{Size: 4}, Offset: 0}, 104 }, 105 }, 106 }, 107 }, 108 }, 109 "type t struct { foo uint32; _ [4]byte; }", 110 }, 111 { 112 &Datasec{ 113 Size: 16, 114 Vars: []VarSecinfo{ 115 {&Var{Name: "s", Type: &Int{Size: 2}, Linkage: StaticVar}, 0, 2}, 116 {&Var{Name: "g", Type: &Int{Size: 4}, Linkage: GlobalVar}, 4, 4}, 117 {&Var{Name: "e", Type: &Int{Size: 8}, Linkage: ExternVar}, 8, 8}, 118 }, 119 }, 120 "type t struct { _ [4]byte; g uint32; _ [8]byte; }", 121 }, 122 } 123 124 for _, test := range tests { 125 t.Run(fmt.Sprint(test.typ), func(t *testing.T) { 126 have := mustGoTypeDeclaration(t, test.typ, nil, nil) 127 if have != test.output { 128 t.Errorf("Unexpected output:\n\t-%s\n\t+%s", test.output, have) 129 } 130 }) 131 } 132 } 133 134 func TestGoTypeDeclarationNamed(t *testing.T) { 135 e1 := &Enum{Name: "e1", Size: 4} 136 s1 := &Struct{ 137 Name: "s1", 138 Size: 4, 139 Members: []Member{ 140 {Name: "frob", Type: e1}, 141 }, 142 } 143 s2 := &Struct{ 144 Name: "s2", 145 Size: 4, 146 Members: []Member{ 147 {Name: "frood", Type: s1}, 148 }, 149 } 150 td := &Typedef{Name: "td", Type: e1} 151 arr := &Array{Nelems: 1, Type: td} 152 153 tests := []struct { 154 typ Type 155 named []Type 156 output string 157 }{ 158 {e1, []Type{e1}, "type t int32"}, 159 {s1, []Type{e1, s1}, "type t struct { frob E1; }"}, 160 {s2, []Type{e1}, "type t struct { frood struct { frob E1; }; }"}, 161 {s2, []Type{e1, s1}, "type t struct { frood S1; }"}, 162 {td, nil, "type t int32"}, 163 {td, []Type{td}, "type t int32"}, 164 {arr, []Type{td}, "type t [1]TD"}, 165 } 166 167 for _, test := range tests { 168 t.Run(fmt.Sprint(test.typ), func(t *testing.T) { 169 names := make(map[Type]string) 170 for _, t := range test.named { 171 names[t] = strings.ToUpper(t.TypeName()) 172 } 173 174 have := mustGoTypeDeclaration(t, test.typ, names, nil) 175 if have != test.output { 176 t.Errorf("Unexpected output:\n\t-%s\n\t+%s", test.output, have) 177 } 178 }) 179 } 180 } 181 182 func TestGoTypeDeclarationQualifiers(t *testing.T) { 183 i := &Int{Size: 4} 184 want := mustGoTypeDeclaration(t, i, nil, nil) 185 186 tests := []struct { 187 typ Type 188 }{ 189 {&Volatile{Type: i}}, 190 {&Const{Type: i}}, 191 {&Restrict{Type: i}}, 192 } 193 194 for _, test := range tests { 195 t.Run(fmt.Sprint(test.typ), func(t *testing.T) { 196 have := mustGoTypeDeclaration(t, test.typ, nil, nil) 197 if have != want { 198 t.Errorf("Unexpected output:\n\t-%s\n\t+%s", want, have) 199 } 200 }) 201 } 202 } 203 204 func TestGoTypeDeclarationCycle(t *testing.T) { 205 s := &Struct{Name: "cycle"} 206 s.Members = []Member{{Name: "f", Type: s}} 207 208 var gf GoFormatter 209 _, err := gf.TypeDeclaration("t", s) 210 if !errors.Is(err, errNestedTooDeep) { 211 t.Fatal("Expected errNestedTooDeep, got", err) 212 } 213 } 214 215 func mustGoTypeDeclaration(tb testing.TB, typ Type, names map[Type]string, id func(string) string) string { 216 tb.Helper() 217 218 gf := GoFormatter{ 219 Names: names, 220 Identifier: id, 221 } 222 223 have, err := gf.TypeDeclaration("t", typ) 224 if err != nil { 225 tb.Fatal(err) 226 } 227 228 _, err = format.Source([]byte(have)) 229 if err != nil { 230 tb.Fatalf("Output can't be formatted: %s\n%s", err, have) 231 } 232 233 return have 234 }