github.com/searKing/golang/go@v1.2.117/reflect/reflect_test.go (about)

     1  // Copyright 2020 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package reflect_test
     6  
     7  import (
     8  	"reflect"
     9  	"strings"
    10  	"testing"
    11  
    12  	reflect_ "github.com/searKing/golang/go/reflect"
    13  )
    14  
    15  func TestParseStructTag(t *testing.T) {
    16  	test := []struct {
    17  		name    string
    18  		tag     string
    19  		exp     []reflect_.SubStructTag
    20  		invalid bool
    21  	}{
    22  		{
    23  			name: "empty tag",
    24  			tag:  "",
    25  		},
    26  		{
    27  			name:    "tag with one key (invalid)",
    28  			tag:     "json",
    29  			invalid: true,
    30  		},
    31  		{
    32  			name: "tag with one key (valid)",
    33  			tag:  `json:""`,
    34  			exp: []reflect_.SubStructTag{
    35  				{
    36  					Key: "json",
    37  				},
    38  			},
    39  		},
    40  		{
    41  			name: "tag with one key and dash name",
    42  			tag:  `json:"-"`,
    43  			exp: []reflect_.SubStructTag{
    44  				{
    45  					Key: "json", Name: "-",
    46  				},
    47  			},
    48  		},
    49  		{
    50  			name: "tag with key and name",
    51  			tag:  `json:"foo"`,
    52  			exp: []reflect_.SubStructTag{
    53  				{
    54  					Key: "json", Name: "foo",
    55  				},
    56  			},
    57  		},
    58  		{
    59  			name: "tag with key, name and option",
    60  			tag:  `json:"foo,omitempty"`,
    61  			exp: []reflect_.SubStructTag{
    62  				{
    63  					Key: "json", Name: "foo", Options: []string{"omitempty"},
    64  				},
    65  			},
    66  		},
    67  		{
    68  			name: "tag with multiple keys",
    69  			tag:  `json:"" yaml:""`,
    70  			exp: []reflect_.SubStructTag{
    71  				{Key: "json"},
    72  				{Key: "yaml"},
    73  			},
    74  		},
    75  		{
    76  			name: "tag with multiple keys and names",
    77  			tag:  `json:"foo" yaml:"bar"`,
    78  			exp: []reflect_.SubStructTag{
    79  				{Key: "json", Name: "foo"},
    80  				{Key: "yaml", Name: "bar"},
    81  			},
    82  		},
    83  		{
    84  			name: "tag with multiple keys, different names and options",
    85  			tag:  `json:"foo,omitempty" yaml:"bar,omitempty"`,
    86  			exp: []reflect_.SubStructTag{
    87  				{Key: "json", Name: "foo", Options: []string{"omitempty"}},
    88  				{Key: "yaml", Name: "bar", Options: []string{"omitempty"}},
    89  			},
    90  		},
    91  		{
    92  			name: "tag with multiple keys, different names and options",
    93  			tag:  `json:"foo" yaml:"bar,omitempty" xml:"-"`,
    94  			exp: []reflect_.SubStructTag{
    95  				{Key: "json", Name: "foo"},
    96  				{Key: "yaml", Name: "bar", Options: []string{"omitempty"}},
    97  				{Key: "xml", Name: "-"},
    98  			},
    99  		},
   100  		{
   101  			name: "tag with quoted name",
   102  			tag:  `json:"foo,bar:\"baz\""`,
   103  			exp: []reflect_.SubStructTag{
   104  				{
   105  					Key: "json", Name: "foo", Options: []string{`bar:"baz"`},
   106  				},
   107  			},
   108  		},
   109  		{
   110  			name:    "tag with trailing space",
   111  			tag:     `json:"foo   " `,
   112  			invalid: true,
   113  		},
   114  		{
   115  			name:    "json tag value with space",
   116  			tag:     `json:"oneof=http https"`,
   117  			invalid: true,
   118  		},
   119  		{
   120  			name: "tag[^json|xml|asn1] value with space",
   121  			tag:  `validate:"oneof=http https"`,
   122  		},
   123  	}
   124  
   125  	for i, ts := range test {
   126  		t.Run(ts.name, func(t *testing.T) {
   127  			tags, err := reflect_.ParseStructTag(ts.tag)
   128  			invalid := err != nil
   129  
   130  			if invalid != ts.invalid {
   131  				t.Errorf("#%d, invalid case\n\twant: %+v\n\tgot : %+v\n\terr : %s", i, ts.invalid, invalid, err)
   132  			}
   133  
   134  			if invalid {
   135  				return
   136  			}
   137  
   138  			for _, tag := range ts.exp {
   139  				got, _ := tags.Get(tag.Key)
   140  				if !reflect.DeepEqual(tag, got) {
   141  					t.Errorf("#%d, parse\n\twant: %#v\n\tgot : %#v", i, tag, got)
   142  				}
   143  			}
   144  
   145  			trimmedInput := strings.TrimSpace(ts.tag)
   146  			got := tags.String()
   147  
   148  			if len(trimmedInput) != len(got) {
   149  				t.Errorf("#%d, parse string\n\twant: %#v\n\tgot : %#v", i, trimmedInput, got)
   150  			}
   151  		})
   152  	}
   153  }
   154  
   155  func TestTags_Get(t *testing.T) {
   156  	tag := `json:"foo,omitempty" yaml:"bar,omitempty"`
   157  
   158  	tags, err := reflect_.ParseStructTag(tag)
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  
   163  	found, ok := tags.Get("json")
   164  	if !ok {
   165  		t.Fatalf("expect %q, go %q", "json", "")
   166  	}
   167  
   168  	t.Run("String", func(t *testing.T) {
   169  		want := `json:"foo,omitempty"`
   170  		if found.String() != want {
   171  			t.Errorf("get\n\twant: %#v\n\tgot : %#v", want, found.String())
   172  		}
   173  	})
   174  	t.Run("Value", func(t *testing.T) {
   175  		want := `foo,omitempty`
   176  		if found.Value() != want {
   177  			t.Errorf("get\n\twant: %#v\n\tgot : %#v", want, found.Value())
   178  		}
   179  	})
   180  }
   181  
   182  func TestTags_Set(t *testing.T) {
   183  	tag := `json:"foo,omitempty" yaml:"bar,omitempty"`
   184  
   185  	tags, err := reflect_.ParseStructTag(tag)
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  	err = tags.Set(reflect_.SubStructTag{
   190  		Key:     "json",
   191  		Name:    "bar",
   192  		Options: []string{},
   193  	})
   194  	if err != nil {
   195  		t.Fatal(err)
   196  	}
   197  
   198  	found, ok := tags.Get("json")
   199  	if !ok {
   200  		t.Fatalf("expect %q, go %q", "json", "")
   201  	}
   202  
   203  	want := `json:"bar"`
   204  	if found.String() != want {
   205  		t.Errorf("set\n\twant: %#v\n\tgot : %#v", want, found.String())
   206  	}
   207  }
   208  
   209  func TestTags_Set_Append(t *testing.T) {
   210  	tag := `json:"foo,omitempty"`
   211  
   212  	tags, err := reflect_.ParseStructTag(tag)
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	err = tags.Set(reflect_.SubStructTag{
   218  		Key:     "yaml",
   219  		Name:    "bar",
   220  		Options: []string{"omitempty"},
   221  	})
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  
   226  	found, ok := tags.Get("yaml")
   227  	if !ok {
   228  		t.Fatalf("expect %q, go %q", "json", "")
   229  	}
   230  
   231  	want := `yaml:"bar,omitempty"`
   232  	if found.String() != want {
   233  		t.Errorf("set append\n\twant: %#v\n\tgot : %#v", want, found.String())
   234  	}
   235  
   236  	wantFull := `json:"foo,omitempty" yaml:"bar,omitempty"`
   237  	got := tags.String()
   238  	if len(got) != len(wantFull) {
   239  		t.Errorf("set append\n\twant: %#v\n\tgot : %#v", wantFull, got)
   240  	}
   241  }
   242  
   243  func TestTags_Set_KeyDoesNotExist(t *testing.T) {
   244  	tag := `json:"foo,omitempty" yaml:"bar,omitempty"`
   245  
   246  	tags, err := reflect_.ParseStructTag(tag)
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  
   251  	err = tags.Set(reflect_.SubStructTag{
   252  		Key:     "",
   253  		Name:    "bar",
   254  		Options: []string{},
   255  	})
   256  	if err == nil {
   257  		t.Fatal("setting tag with a nonexisting key should error")
   258  	}
   259  }
   260  
   261  func TestTags_Delete(t *testing.T) {
   262  	tag := `json:"foo,omitempty" yaml:"bar,omitempty" xml:"-"`
   263  
   264  	tags, err := reflect_.ParseStructTag(tag)
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  
   269  	tags.Delete("xml")
   270  	if len(tags.Keys()) != 2 {
   271  		t.Fatalf("tag length should be 2, have %d", len(tags.Keys()))
   272  	}
   273  
   274  	found, ok := tags.Get("json")
   275  	if !ok {
   276  		t.Fatalf("expect %q, go %q", "json", "")
   277  	}
   278  
   279  	want := `json:"foo,omitempty"`
   280  	if found.String() != want {
   281  		t.Errorf("delete\n\twant: %#v\n\tgot : %#v", want, found.String())
   282  	}
   283  
   284  	wantFull := `json:"foo,omitempty" yaml:"bar,omitempty"`
   285  	if len(tags.String()) != len(wantFull) {
   286  		t.Errorf("delete\n\twant: %#v\n\tgot : %#v", wantFull, tags.String())
   287  	}
   288  }
   289  
   290  func TestTags_DeleteOptions(t *testing.T) {
   291  	tag := `json:"foo,omitempty" yaml:"bar,omitempty,omitempty" xml:"-"`
   292  
   293  	tags, err := reflect_.ParseStructTag(tag)
   294  	if err != nil {
   295  		t.Fatal(err)
   296  	}
   297  
   298  	tags.DeleteOptions("json", "omitempty")
   299  
   300  	want := `json:"foo" yaml:"bar,omitempty,omitempty" xml:"-"`
   301  	if len(tags.String()) != len(want) {
   302  		t.Errorf("delete option\n\twant: %#v\n\tgot : %#v", want, tags.String())
   303  	}
   304  
   305  	tags.DeleteOptions("yaml", "omitempty")
   306  	want = `json:"foo" yaml:"bar" xml:"-"`
   307  	if len(tags.String()) != len(want) {
   308  		t.Errorf("delete option\n\twant: %#v\n\tgot : %#v", want, tags.String())
   309  	}
   310  }
   311  
   312  func TestTags_AddOption(t *testing.T) {
   313  	tag := `json:"foo" yaml:"bar,omitempty" xml:"-"`
   314  
   315  	tags, err := reflect_.ParseStructTag(tag)
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  
   320  	tags.AddOptions("json", "omitempty")
   321  
   322  	want := `json:"foo,omitempty" yaml:"bar,omitempty" xml:"-"`
   323  	if len(tags.String()) != len(want) {
   324  		t.Errorf("add options\n\twant: %#v\n\tgot : %#v", want, tags.String())
   325  	}
   326  
   327  	// this shouldn't change anything
   328  	tags.AddOptions("yaml", "omitempty")
   329  
   330  	want = `json:"foo,omitempty" yaml:"bar,omitempty" xml:"-"`
   331  	if len(tags.String()) != len(want) {
   332  		t.Errorf("add options\n\twant: %#v\n\tgot : %#v", want, tags.String())
   333  	}
   334  
   335  	// this should append to the existing
   336  	tags.AddOptions("yaml", "omitempty", "flatten")
   337  	want = `json:"foo,omitempty" yaml:"bar,omitempty,flatten" xml:"-"`
   338  	if len(tags.String()) != len(want) {
   339  		t.Errorf("add options\n\twant: %#v\n\tgot : %#v", want, tags.String())
   340  	}
   341  }
   342  
   343  func TestTags_String(t *testing.T) {
   344  	tag := `json:"foo" yaml:"bar,omitempty" xml:"-"`
   345  
   346  	tags, err := reflect_.ParseStructTag(tag)
   347  	if err != nil {
   348  		t.Fatal(err)
   349  	}
   350  
   351  	got := tags.String()
   352  	if len(got) != len(tag) {
   353  		t.Errorf("string\n\twant: %#v\n\tgot : %#v", tag, got)
   354  	}
   355  }
   356  
   357  func TestTags_OrderedString(t *testing.T) {
   358  	tag := `json:"foo" yaml:"bar,omitempty" xml:"-"`
   359  
   360  	tags, err := reflect_.ParseStructTag(tag)
   361  	if err != nil {
   362  		t.Fatal(err)
   363  	}
   364  
   365  	got := tags.OrderedString()
   366  	want := `json:"foo" yaml:"bar,omitempty" xml:"-"`
   367  
   368  	if got != want {
   369  		t.Errorf("string\n\twant: %#v\n\tgot : %#v", want, got)
   370  	}
   371  }
   372  
   373  func TestTags_SortedString(t *testing.T) {
   374  	tag := `json:"foo" yaml:"bar,omitempty" xml:"-"`
   375  
   376  	tags, err := reflect_.ParseStructTag(tag)
   377  	if err != nil {
   378  		t.Fatal(err)
   379  	}
   380  
   381  	got := tags.SortedString()
   382  	want := `json:"foo" xml:"-" yaml:"bar,omitempty"`
   383  
   384  	if got != want {
   385  		t.Errorf("string\n\twant: %#v\n\tgot : %#v", want, got)
   386  	}
   387  }
   388  
   389  func TestTags_AstString(t *testing.T) {
   390  	tag := `json:"foo" yaml:"bar,omitempty" xml:"-"`
   391  
   392  	tags, err := reflect_.ParseStructTag(tag)
   393  	if err != nil {
   394  		t.Fatal(err)
   395  	}
   396  
   397  	got := tags.AstString()
   398  	want := "`json:\"foo\" yaml:\"bar,omitempty\" xml:\"-\"`"
   399  	if len(got) != len(want) {
   400  		t.Errorf("string\n\twant: %#v\n\tgot : %#v", want, got)
   401  	}
   402  }