1package btf 2 3import ( 4 "fmt" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8) 9 10func TestSizeof(t *testing.T) { 11 testcases := []struct { 12 size int 13 typ Type 14 }{ 15 {0, (*Void)(nil)}, 16 {1, &Int{Size: 1}}, 17 {4, &Enum{}}, 18 {0, &Array{Type: &Pointer{Target: (*Void)(nil)}, Nelems: 0}}, 19 {12, &Array{Type: &Enum{}, Nelems: 3}}, 20 } 21 22 for _, tc := range testcases { 23 name := fmt.Sprint(tc.typ) 24 t.Run(name, func(t *testing.T) { 25 have, err := Sizeof(tc.typ) 26 if err != nil { 27 t.Fatal("Can't calculate size:", err) 28 } 29 if have != tc.size { 30 t.Errorf("Expected size %d, got %d", tc.size, have) 31 } 32 }) 33 } 34} 35 36func TestCopyType(t *testing.T) { 37 _ = copyType((*Void)(nil)) 38 39 in := &Int{Size: 4} 40 out := copyType(in) 41 42 in.Size = 8 43 if size := out.(*Int).Size; size != 4 { 44 t.Error("Copy doesn't make a copy, expected size 4, got", size) 45 } 46 47 t.Run("cyclical", func(t *testing.T) { 48 _ = copyType(newCyclicalType(2)) 49 }) 50} 51 52// The following are valid Types. 53// 54// There currently is no better way to document which 55// types implement an interface. 56func ExampleType_validTypes() { 57 var t Type 58 t = &Void{} 59 t = &Int{} 60 t = &Pointer{} 61 t = &Array{} 62 t = &Struct{} 63 t = &Union{} 64 t = &Enum{} 65 t = &Fwd{} 66 t = &Typedef{} 67 t = &Volatile{} 68 t = &Const{} 69 t = &Restrict{} 70 t = &Func{} 71 t = &FuncProto{} 72 t = &Var{} 73 t = &Datasec{} 74 _ = t 75} 76 77func TestType(t *testing.T) { 78 types := []func() Type{ 79 func() Type { return &Void{} }, 80 func() Type { return &Int{} }, 81 func() Type { return &Pointer{Target: &Void{}} }, 82 func() Type { return &Array{Type: &Int{}} }, 83 func() Type { 84 return &Struct{ 85 Members: []Member{{Type: &Void{}}}, 86 } 87 }, 88 func() Type { 89 return &Union{ 90 Members: []Member{{Type: &Void{}}}, 91 } 92 }, 93 func() Type { return &Enum{} }, 94 func() Type { return &Fwd{Name: "thunk"} }, 95 func() Type { return &Typedef{Type: &Void{}} }, 96 func() Type { return &Volatile{Type: &Void{}} }, 97 func() Type { return &Const{Type: &Void{}} }, 98 func() Type { return &Restrict{Type: &Void{}} }, 99 func() Type { return &Func{Name: "foo", Type: &Void{}} }, 100 func() Type { 101 return &FuncProto{ 102 Params: []FuncParam{{Name: "bar", Type: &Void{}}}, 103 Return: &Void{}, 104 } 105 }, 106 func() Type { return &Var{Type: &Void{}} }, 107 func() Type { 108 return &Datasec{ 109 Vars: []VarSecinfo{{Type: &Void{}}}, 110 } 111 }, 112 } 113 114 compareTypes := cmp.Comparer(func(a, b *Type) bool { 115 return a == b 116 }) 117 118 for _, fn := range types { 119 typ := fn() 120 t.Run(fmt.Sprintf("%T", typ), func(t *testing.T) { 121 if typ == typ.copy() { 122 t.Error("Copy doesn't copy") 123 } 124 125 var first, second copyStack 126 typ.walk(&first) 127 typ.walk(&second) 128 129 if diff := cmp.Diff(first, second, compareTypes); diff != "" { 130 t.Errorf("Walk mismatch (-want +got):\n%s", diff) 131 } 132 }) 133 } 134} 135 136func newCyclicalType(n int) Type { 137 ptr := &Pointer{} 138 prev := Type(ptr) 139 for i := 0; i < n; i++ { 140 switch i % 5 { 141 case 0: 142 prev = &Struct{ 143 Members: []Member{ 144 {Type: prev}, 145 }, 146 } 147 148 case 1: 149 prev = &Const{Type: prev} 150 case 2: 151 prev = &Volatile{Type: prev} 152 case 3: 153 prev = &Typedef{Type: prev} 154 case 4: 155 prev = &Array{Type: prev} 156 } 157 } 158 ptr.Target = prev 159 return ptr 160} 161