github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/config/struct_keys_test.go (about) 1 package config_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/go-test/deep" 8 "github.com/treeverse/lakefs/pkg/config" 9 ) 10 11 const ( 12 tagName = "test" 13 squashTagValue = "squash" 14 ) 15 16 func TestStructKeys_Simple(t *testing.T) { 17 type s struct { 18 A int 19 B string 20 C *float64 21 D []rune 22 } 23 24 keys := config.GetStructKeys(reflect.TypeOf(s{}), tagName, squashTagValue) 25 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 26 t.Error("wrong keys for struct: ", diffs) 27 } 28 29 keys = config.GetStructKeys(reflect.TypeOf(&s{}), tagName, squashTagValue) 30 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 31 t.Error("wrong keys for pointer to struct: ", diffs) 32 } 33 34 ps := &s{} 35 keys = config.GetStructKeys(reflect.TypeOf(&ps), tagName, squashTagValue) 36 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 37 t.Error("wrong keys for pointer to pointer to struct: ", diffs) 38 } 39 } 40 41 func TestStructKeys_Nested(t *testing.T) { 42 type s struct { 43 A struct { 44 X string 45 Y int 46 } 47 B ***struct { 48 Z float32 49 W float64 50 } 51 } 52 53 keys := config.GetStructKeys(reflect.TypeOf(s{}), tagName, squashTagValue) 54 if diffs := deep.Equal(keys, []string{"a.x", "a.y", "b.z", "b.w"}); diffs != nil { 55 t.Error("wrong keys for struct: ", diffs) 56 } 57 } 58 59 func TestStructKeys_SimpleTagged(t *testing.T) { 60 type s struct { 61 A int `test:"Aaa"` 62 B int `toast:"bee"` 63 c int `test:"ccc" toast:"sea"` 64 } 65 // make sure we use the struct as it holds private members 66 _ = s{A: 1, B: 2, c: 3} 67 68 keys := config.GetStructKeys(reflect.TypeOf(s{}), tagName, squashTagValue) 69 if diffs := deep.Equal(keys, []string{"Aaa", "b", "ccc"}); diffs != nil { 70 t.Error("wrong keys for struct: ", diffs) 71 } 72 } 73 74 func TestStructKeys_NestedTagged(t *testing.T) { 75 type s struct { 76 A struct { 77 X int `test:"eks"` 78 BE string 79 } `test:"aaa"` 80 B **struct { 81 Gamma int32 82 Delta uint8 `test:"dee"` 83 } 84 } 85 86 keys := config.GetStructKeys(reflect.TypeOf(s{}), tagName, squashTagValue) 87 if diffs := deep.Equal(keys, []string{"aaa.eks", "aaa.be", "b.gamma", "b.dee"}); diffs != nil { 88 t.Error("wrong keys for struct: ", diffs) 89 } 90 } 91 92 func TestStructKeys_Squash(t *testing.T) { 93 type I struct { 94 A int 95 B int 96 } 97 type J struct { 98 C uint 99 D uint 100 } 101 type s struct { 102 I `test:",squash"` 103 J `test:"ignore,squash"` 104 } 105 106 keys := config.GetStructKeys(reflect.TypeOf(s{}), tagName, squashTagValue) 107 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 108 t.Error("wrong keys for struct: ", diffs) 109 } 110 } 111 112 func TestValidateMissingRequired_SimpleRequired(t *testing.T) { 113 type s struct { 114 A int `validate:"required"` 115 AA int 116 B string `validate:"x,required,y"` 117 BB string `validate:"unrequired"` 118 C *float64 `validate:"0,required"` 119 CC *float64 `validate:"unrequired,1,2,3"` 120 D []rune `validate:"required,2"` 121 DD []rune 122 } 123 124 keys := config.ValidateMissingRequiredKeys(s{}, tagName, squashTagValue) 125 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 126 t.Error("wrong missing keys for struct: ", diffs) 127 } 128 keys = config.ValidateMissingRequiredKeys(&s{}, tagName, squashTagValue) 129 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 130 t.Error("wrong missing keys for pointer to struct: ", diffs) 131 } 132 ps := &s{} 133 keys = config.ValidateMissingRequiredKeys(&ps, tagName, squashTagValue) 134 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 135 t.Error("wrong missing keys for pointer to pointer to struct: ", diffs) 136 } 137 } 138 139 func TestValidateMissingRequired_SimpleNotMissing(t *testing.T) { 140 type s struct { 141 A int `validate:"required"` 142 AA int 143 B string `validate:"x,required,y"` 144 BB string `validate:"unrequired"` 145 C *float64 `validate:"0,required"` 146 CC *float64 `validate:"unrequired,1,2,3"` 147 D []rune `validate:"required,2"` 148 DD []rune 149 } 150 151 c := 12.34 152 cases := []struct { 153 Value s 154 MissingRequired []string 155 }{ 156 {s{A: 2, C: &c}, []string{"b", "d"}}, 157 {s{AA: 22, B: "foo", D: []rune{'a', 'b', 'c'}}, []string{"a", "c"}}, 158 } 159 160 for _, c := range cases { 161 keys := config.ValidateMissingRequiredKeys(c.Value, tagName, squashTagValue) 162 if diffs := deep.Equal(keys, c.MissingRequired); diffs != nil { 163 t.Errorf("wrong missing keys for %+v: %s", c.Value, diffs) 164 } 165 } 166 } 167 168 func TestValidateMissingRequired_Nested(t *testing.T) { 169 type B struct { 170 Z float32 `validate:"required"` 171 W float64 172 } 173 type s struct { 174 A struct { 175 X string 176 Y int `validate:"required"` 177 } 178 B ***B `validate:"required"` 179 } 180 181 keys := config.ValidateMissingRequiredKeys(s{}, tagName, squashTagValue) 182 if diffs := deep.Equal(keys, []string{"a.y", "b"}); diffs != nil { 183 t.Error("wrong missing keys for empty struct: ", diffs) 184 } 185 186 b := B{} 187 pb := &b 188 ppb := &pb 189 keys = config.ValidateMissingRequiredKeys(&s{B: &ppb}, tagName, squashTagValue) 190 if diffs := deep.Equal(keys, []string{"a.y", "b.z"}); diffs != nil { 191 t.Error("wrong missing keys for struct with empty optional: ", diffs) 192 } 193 } 194 195 func TestValidateMissingRequired_NestedNotMissing(t *testing.T) { 196 type A struct { 197 X string 198 Y int `validate:"required"` 199 } 200 type B struct { 201 Z float32 `validate:"required"` 202 W float64 203 } 204 type s struct { 205 A A 206 B ***B `validate:"required"` 207 } 208 209 ptr3 := func(b B) ***B { pb := &b; ppb := &pb; return &ppb } 210 ptr2 := func(b *B) ***B { pb := &b; return &pb } 211 ptr1 := func(b **B) ***B { return &b } 212 213 cases := []struct { 214 Name string 215 Value s 216 MissingRequired []string 217 }{ 218 {"s{}", s{}, []string{"a.y", "b"}}, 219 {"s{A: A{Y: 7}, B: &&&B{}}", s{A: A{Y: 7}, B: ptr3(B{})}, []string{"b.z"}}, 220 {"s{B: &&&B{Z: 1.23}}", s{B: ptr3(B{Z: 1.23})}, []string{"a.y"}}, 221 // Required field B is present but leads nowhere: all good(!). 222 {"s{A: A{Y: 7}, B: &nil", s{A: A{Y: 7}, B: ptr1(nil)}, nil}, 223 // Required field B is present but leads nowhere: all good(!). 224 {"s{A: A{Y: 7}, B: &&nil}", s{A: A{Y: 7}, B: ptr2(nil)}, nil}, 225 } 226 227 for _, c := range cases { 228 keys := config.ValidateMissingRequiredKeys(c.Value, tagName, squashTagValue) 229 if diffs := deep.Equal(keys, c.MissingRequired); diffs != nil { 230 t.Errorf("%s: wrong keys for %+v: %s", c.Name, c.Value, diffs) 231 } 232 } 233 } 234 235 func TestValidateMissingRequired_SimpleTagged(t *testing.T) { 236 type s struct { 237 A int `test:"Aaa" validate:"required"` 238 B int `toast:"bee" validate:"required"` 239 c int `test:"ccc" toast:"sea" validate:"required"` 240 } 241 // make sure we use the struct as it holds private members 242 _ = s{A: 1, B: 2, c: 3} 243 244 keys := config.ValidateMissingRequiredKeys(s{}, tagName, squashTagValue) 245 if diffs := deep.Equal(keys, []string{"Aaa", "b", "ccc"}); diffs != nil { 246 t.Error("wrong keys for struct: ", diffs) 247 } 248 } 249 250 func TestValidateMissingRequired_NestedTagged(t *testing.T) { 251 type B struct { 252 Gamma int32 `validate:"required"` 253 Delta uint8 `test:"dee" validate:"required"` 254 } 255 type s struct { 256 A struct { 257 X int `test:"eks" validate:"required"` 258 BE string `validate:"required"` 259 } `test:"aaa"` 260 B *B 261 } 262 263 keys := config.ValidateMissingRequiredKeys(s{}, tagName, squashTagValue) 264 if diffs := deep.Equal(keys, []string{"aaa.eks", "aaa.be"}); diffs != nil { 265 t.Error("wrong missing keys for missing optional: ", diffs) 266 } 267 268 b := B{} 269 keys = config.ValidateMissingRequiredKeys(s{B: &b}, tagName, squashTagValue) 270 if diffs := deep.Equal(keys, []string{"aaa.eks", "aaa.be", "b.gamma", "b.dee"}); diffs != nil { 271 t.Error("wrong missing keys for present optional missing fields: ", diffs) 272 } 273 } 274 275 func TestValidateMissingRequired_Squash(t *testing.T) { 276 type I struct { 277 A int `validate:"required"` 278 B int `validate:"required"` 279 } 280 type J struct { 281 C uint `validate:"required"` 282 D uint `validate:"required"` 283 } 284 type s struct { 285 I `test:",squash"` 286 J `test:"ignore,squash"` 287 } 288 289 keys := config.ValidateMissingRequiredKeys(s{}, tagName, squashTagValue) 290 if diffs := deep.Equal(keys, []string{"a", "b", "c", "d"}); diffs != nil { 291 t.Error("wrong missing keys for struct: ", diffs) 292 } 293 }