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  }