...

Source file src/github.com/mitchellh/reflectwalk/reflectwalk_test.go

Documentation: github.com/mitchellh/reflectwalk

     1  package reflectwalk
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  )
     8  
     9  type TestEnterExitWalker struct {
    10  	Locs []Location
    11  }
    12  
    13  func (t *TestEnterExitWalker) Enter(l Location) error {
    14  	if t.Locs == nil {
    15  		t.Locs = make([]Location, 0, 5)
    16  	}
    17  
    18  	t.Locs = append(t.Locs, l)
    19  	return nil
    20  }
    21  
    22  func (t *TestEnterExitWalker) Exit(l Location) error {
    23  	t.Locs = append(t.Locs, l)
    24  	return nil
    25  }
    26  
    27  type TestPointerWalker struct {
    28  	pointers []bool
    29  	count    int
    30  	enters   int
    31  	exits    int
    32  }
    33  
    34  func (t *TestPointerWalker) PointerEnter(v bool) error {
    35  	t.pointers = append(t.pointers, v)
    36  	t.enters++
    37  	if v {
    38  		t.count++
    39  	}
    40  	return nil
    41  }
    42  
    43  func (t *TestPointerWalker) PointerExit(v bool) error {
    44  	t.exits++
    45  	if t.pointers[len(t.pointers)-1] != v {
    46  		return fmt.Errorf("bad pointer exit '%t' at exit %d", v, t.exits)
    47  	}
    48  	t.pointers = t.pointers[:len(t.pointers)-1]
    49  	return nil
    50  }
    51  
    52  type TestPointerValueWalker struct {
    53  	skip     bool
    54  	pointers []reflect.Type
    55  }
    56  
    57  func (t *TestPointerValueWalker) Pointer(v reflect.Value) error {
    58  	t.pointers = append(t.pointers, v.Type())
    59  	if t.skip {
    60  		return SkipEntry
    61  	}
    62  
    63  	return nil
    64  }
    65  
    66  type TestPrimitiveWalker struct {
    67  	Value reflect.Value
    68  }
    69  
    70  func (t *TestPrimitiveWalker) Primitive(v reflect.Value) error {
    71  	t.Value = v
    72  	return nil
    73  }
    74  
    75  type TestPrimitiveCountWalker struct {
    76  	Count int
    77  }
    78  
    79  func (t *TestPrimitiveCountWalker) Primitive(v reflect.Value) error {
    80  	t.Count += 1
    81  	return nil
    82  }
    83  
    84  type TestPrimitiveReplaceWalker struct {
    85  	Value reflect.Value
    86  }
    87  
    88  func (t *TestPrimitiveReplaceWalker) Primitive(v reflect.Value) error {
    89  	v.Set(reflect.ValueOf("bar"))
    90  	return nil
    91  }
    92  
    93  type TestMapWalker struct {
    94  	MapVal reflect.Value
    95  	Keys   map[string]bool
    96  	Values map[string]bool
    97  }
    98  
    99  func (t *TestMapWalker) Map(m reflect.Value) error {
   100  	t.MapVal = m
   101  	return nil
   102  }
   103  
   104  func (t *TestMapWalker) MapElem(m, k, v reflect.Value) error {
   105  	if t.Keys == nil {
   106  		t.Keys = make(map[string]bool)
   107  		t.Values = make(map[string]bool)
   108  	}
   109  
   110  	t.Keys[k.Interface().(string)] = true
   111  	t.Values[v.Interface().(string)] = true
   112  	return nil
   113  }
   114  
   115  type TestMapElemReplaceWalker struct {
   116  	ValueFn func(v reflect.Value) reflect.Value
   117  }
   118  
   119  func (t *TestMapElemReplaceWalker) Map(m reflect.Value) error {
   120  	return nil
   121  }
   122  
   123  func (t *TestMapElemReplaceWalker) MapElem(m, k, v reflect.Value) error {
   124  	m.SetMapIndex(k, t.ValueFn(v))
   125  	return nil
   126  }
   127  
   128  type TestSliceWalker struct {
   129  	Count    int
   130  	SliceVal reflect.Value
   131  }
   132  
   133  func (t *TestSliceWalker) Slice(v reflect.Value) error {
   134  	t.SliceVal = v
   135  	return nil
   136  }
   137  
   138  func (t *TestSliceWalker) SliceElem(int, reflect.Value) error {
   139  	t.Count++
   140  	return nil
   141  }
   142  
   143  type TestArrayWalker struct {
   144  	Count    int
   145  	ArrayVal reflect.Value
   146  }
   147  
   148  func (t *TestArrayWalker) Array(v reflect.Value) error {
   149  	t.ArrayVal = v
   150  	return nil
   151  }
   152  
   153  func (t *TestArrayWalker) ArrayElem(int, reflect.Value) error {
   154  	t.Count++
   155  	return nil
   156  }
   157  
   158  type TestStructWalker struct {
   159  	Fields []string
   160  }
   161  
   162  func (t *TestStructWalker) Struct(v reflect.Value) error {
   163  	return nil
   164  }
   165  
   166  func (t *TestStructWalker) StructField(sf reflect.StructField, v reflect.Value) error {
   167  	if t.Fields == nil {
   168  		t.Fields = make([]string, 0, 1)
   169  	}
   170  
   171  	t.Fields = append(t.Fields, sf.Name)
   172  	return nil
   173  }
   174  
   175  func TestTestStructs(t *testing.T) {
   176  	var raw interface{}
   177  	raw = new(TestEnterExitWalker)
   178  	if _, ok := raw.(EnterExitWalker); !ok {
   179  		t.Fatal("EnterExitWalker is bad")
   180  	}
   181  
   182  	raw = new(TestPrimitiveWalker)
   183  	if _, ok := raw.(PrimitiveWalker); !ok {
   184  		t.Fatal("PrimitiveWalker is bad")
   185  	}
   186  
   187  	raw = new(TestMapWalker)
   188  	if _, ok := raw.(MapWalker); !ok {
   189  		t.Fatal("MapWalker is bad")
   190  	}
   191  
   192  	raw = new(TestSliceWalker)
   193  	if _, ok := raw.(SliceWalker); !ok {
   194  		t.Fatal("SliceWalker is bad")
   195  	}
   196  
   197  	raw = new(TestArrayWalker)
   198  	if _, ok := raw.(ArrayWalker); !ok {
   199  		t.Fatal("ArrayWalker is bad")
   200  	}
   201  
   202  	raw = new(TestStructWalker)
   203  	if _, ok := raw.(StructWalker); !ok {
   204  		t.Fatal("StructWalker is bad")
   205  	}
   206  }
   207  
   208  func TestWalk_Basic(t *testing.T) {
   209  	w := new(TestPrimitiveWalker)
   210  
   211  	type S struct {
   212  		Foo string
   213  	}
   214  
   215  	data := &S{
   216  		Foo: "foo",
   217  	}
   218  
   219  	err := Walk(data, w)
   220  	if err != nil {
   221  		t.Fatalf("err: %s", err)
   222  	}
   223  
   224  	if w.Value.Kind() != reflect.String {
   225  		t.Fatalf("bad: %#v", w.Value)
   226  	}
   227  }
   228  
   229  func TestWalk_Basic_Replace(t *testing.T) {
   230  	w := new(TestPrimitiveReplaceWalker)
   231  
   232  	type S struct {
   233  		Foo string
   234  		Bar []interface{}
   235  	}
   236  
   237  	data := &S{
   238  		Foo: "foo",
   239  		Bar: []interface{}{[]string{"what"}},
   240  	}
   241  
   242  	err := Walk(data, w)
   243  	if err != nil {
   244  		t.Fatalf("err: %s", err)
   245  	}
   246  
   247  	if data.Foo != "bar" {
   248  		t.Fatalf("bad: %#v", data.Foo)
   249  	}
   250  	if data.Bar[0].([]string)[0] != "bar" {
   251  		t.Fatalf("bad: %#v", data.Bar)
   252  	}
   253  }
   254  
   255  func TestWalk_Basic_ReplaceInterface(t *testing.T) {
   256  	w := new(TestPrimitiveReplaceWalker)
   257  
   258  	type S struct {
   259  		Foo []interface{}
   260  	}
   261  
   262  	data := &S{
   263  		Foo: []interface{}{"foo"},
   264  	}
   265  
   266  	err := Walk(data, w)
   267  	if err != nil {
   268  		t.Fatalf("err: %s", err)
   269  	}
   270  }
   271  
   272  func TestWalk_EnterExit(t *testing.T) {
   273  	w := new(TestEnterExitWalker)
   274  
   275  	type S struct {
   276  		A string
   277  		M map[string]string
   278  	}
   279  
   280  	data := &S{
   281  		A: "foo",
   282  		M: map[string]string{
   283  			"a": "b",
   284  		},
   285  	}
   286  
   287  	err := Walk(data, w)
   288  	if err != nil {
   289  		t.Fatalf("err: %s", err)
   290  	}
   291  
   292  	expected := []Location{
   293  		WalkLoc,
   294  		Struct,
   295  		StructField,
   296  		StructField,
   297  		StructField,
   298  		Map,
   299  		MapKey,
   300  		MapKey,
   301  		MapValue,
   302  		MapValue,
   303  		Map,
   304  		StructField,
   305  		Struct,
   306  		WalkLoc,
   307  	}
   308  	if !reflect.DeepEqual(w.Locs, expected) {
   309  		t.Fatalf("Bad: %#v", w.Locs)
   310  	}
   311  }
   312  
   313  func TestWalk_Interface(t *testing.T) {
   314  	w := new(TestPrimitiveCountWalker)
   315  
   316  	type S struct {
   317  		Foo string
   318  		Bar []interface{}
   319  	}
   320  
   321  	var data interface{} = &S{
   322  		Foo: "foo",
   323  		Bar: []interface{}{[]string{"bar", "what"}, "baz"},
   324  	}
   325  
   326  	err := Walk(data, w)
   327  	if err != nil {
   328  		t.Fatalf("err: %s", err)
   329  	}
   330  
   331  	if w.Count != 4 {
   332  		t.Fatalf("bad: %#v", w.Count)
   333  	}
   334  }
   335  
   336  func TestWalk_Interface_nil(t *testing.T) {
   337  	w := new(TestPrimitiveCountWalker)
   338  
   339  	type S struct {
   340  		Bar interface{}
   341  	}
   342  
   343  	var data interface{} = &S{}
   344  
   345  	err := Walk(data, w)
   346  	if err != nil {
   347  		t.Fatalf("err: %s", err)
   348  	}
   349  }
   350  
   351  func TestWalk_Map(t *testing.T) {
   352  	w := new(TestMapWalker)
   353  
   354  	type S struct {
   355  		Foo map[string]string
   356  	}
   357  
   358  	data := &S{
   359  		Foo: map[string]string{
   360  			"foo": "foov",
   361  			"bar": "barv",
   362  		},
   363  	}
   364  
   365  	err := Walk(data, w)
   366  	if err != nil {
   367  		t.Fatalf("err: %s", err)
   368  	}
   369  
   370  	if !reflect.DeepEqual(w.MapVal.Interface(), data.Foo) {
   371  		t.Fatalf("Bad: %#v", w.MapVal.Interface())
   372  	}
   373  
   374  	expectedK := map[string]bool{"foo": true, "bar": true}
   375  	if !reflect.DeepEqual(w.Keys, expectedK) {
   376  		t.Fatalf("Bad keys: %#v", w.Keys)
   377  	}
   378  
   379  	expectedV := map[string]bool{"foov": true, "barv": true}
   380  	if !reflect.DeepEqual(w.Values, expectedV) {
   381  		t.Fatalf("Bad values: %#v", w.Values)
   382  	}
   383  }
   384  
   385  func TestWalk_Map_ReplaceValue(t *testing.T) {
   386  	w := &TestMapElemReplaceWalker{
   387  		ValueFn: func(v reflect.Value) reflect.Value {
   388  			if v.Type().Kind() == reflect.String {
   389  				return reflect.ValueOf("replaced")
   390  			}
   391  
   392  			if v.Type().Kind() == reflect.Interface {
   393  				if elem := v.Elem(); elem.Type() == reflect.TypeOf(map[string]interface{}{}) {
   394  					newMap := make(map[string]interface{})
   395  					for _, k := range elem.MapKeys() {
   396  						newMap[k.String()] = elem.MapIndex(k).Interface()
   397  					}
   398  					newMap["extra-replaced"] = "not-replaced"
   399  					return reflect.ValueOf(newMap)
   400  				} else if elem.Type().Kind() == reflect.String {
   401  					return reflect.ValueOf("replaced")
   402  				}
   403  			}
   404  
   405  			return v
   406  		},
   407  	}
   408  
   409  	type S struct {
   410  		Foo map[string]interface{}
   411  	}
   412  
   413  	data := &S{
   414  		Foo: map[string]interface{}{
   415  			"foo": map[string]interface{}{
   416  				"bar": map[string]string{"baz": "should-get-replaced"},
   417  			},
   418  		},
   419  	}
   420  
   421  	expected := &S{
   422  		Foo: map[string]interface{}{
   423  			"foo": map[string]interface{}{
   424  				"bar":            map[string]string{"baz": "replaced"},
   425  				"extra-replaced": "replaced",
   426  			},
   427  		},
   428  	}
   429  
   430  	err := Walk(data, w)
   431  	if err != nil {
   432  		t.Fatalf("err: %v", err)
   433  	}
   434  
   435  	if !reflect.DeepEqual(data, expected) {
   436  		t.Fatalf("Values not equal: %#v", data)
   437  	}
   438  }
   439  
   440  func TestWalk_Pointer(t *testing.T) {
   441  	w := new(TestPointerWalker)
   442  
   443  	type S struct {
   444  		Foo string
   445  		Bar *string
   446  		Baz **string
   447  	}
   448  
   449  	s := ""
   450  	sp := &s
   451  
   452  	data := &S{
   453  		Baz: &sp,
   454  	}
   455  
   456  	err := Walk(data, w)
   457  	if err != nil {
   458  		t.Fatalf("err: %s", err)
   459  	}
   460  
   461  	if w.enters != 5 {
   462  		t.Fatal("expected 4 values, saw", w.enters)
   463  	}
   464  
   465  	if w.count != 4 {
   466  		t.Fatal("exptec 3 pointers, saw", w.count)
   467  	}
   468  
   469  	if w.exits != w.enters {
   470  		t.Fatalf("number of enters (%d) and exits (%d) don't match", w.enters, w.exits)
   471  	}
   472  }
   473  
   474  func TestWalk_PointerPointer(t *testing.T) {
   475  	w := new(TestPointerWalker)
   476  
   477  	s := ""
   478  	sp := &s
   479  	pp := &sp
   480  
   481  	err := Walk(pp, w)
   482  	if err != nil {
   483  		t.Fatalf("err: %s", err)
   484  	}
   485  
   486  	if w.enters != 2 {
   487  		t.Fatal("expected 2 values, saw", w.enters)
   488  	}
   489  
   490  	if w.count != 2 {
   491  		t.Fatal("expected 2 pointers, saw", w.count)
   492  	}
   493  
   494  	if w.exits != w.enters {
   495  		t.Fatalf("number of enters (%d) and exits (%d) don't match", w.enters, w.exits)
   496  	}
   497  }
   498  
   499  func TestWalk_PointerValue(t *testing.T) {
   500  	type X struct{}
   501  	type T struct {
   502  		x *X
   503  	}
   504  
   505  	v := &T{x: &X{}}
   506  
   507  	expected := []reflect.Type{
   508  		reflect.TypeOf(v),
   509  		reflect.TypeOf(v.x),
   510  	}
   511  
   512  	w := new(TestPointerValueWalker)
   513  	err := Walk(v, w)
   514  	if err != nil {
   515  		t.Fatal(err)
   516  	}
   517  
   518  	if !reflect.DeepEqual(expected, w.pointers) {
   519  		t.Fatalf("unexpected pointer order or length (expected len=%d, actual len=%d)", len(expected), len(w.pointers))
   520  	}
   521  }
   522  
   523  func TestWalk_PointerValueSkip(t *testing.T) {
   524  	type T struct{}
   525  	type W struct {
   526  		TestPointerValueWalker
   527  		TestPointerWalker
   528  	}
   529  
   530  	v := &T{}
   531  	w := &W{
   532  		TestPointerValueWalker: TestPointerValueWalker{
   533  			skip: true,
   534  		},
   535  	}
   536  	err := Walk(v, w)
   537  	if err != nil {
   538  		t.Fatal(err)
   539  	}
   540  
   541  	if len(w.TestPointerValueWalker.pointers) != 1 {
   542  		t.Errorf("expected len=1, got len=%d", len(w.TestPointerValueWalker.pointers))
   543  	}
   544  
   545  	if w.TestPointerValueWalker.pointers[0] != reflect.TypeOf(v) {
   546  		t.Error("pointer value type mismatch")
   547  	}
   548  
   549  	if w.enters != 0 || w.exits != 0 {
   550  		t.Error("should have been skipped and have zero enters or exits")
   551  	}
   552  }
   553  
   554  func TestWalk_Slice(t *testing.T) {
   555  	w := new(TestSliceWalker)
   556  
   557  	type S struct {
   558  		Foo []string
   559  	}
   560  
   561  	data := &S{
   562  		Foo: []string{"a", "b", "c"},
   563  	}
   564  
   565  	err := Walk(data, w)
   566  	if err != nil {
   567  		t.Fatalf("err: %s", err)
   568  	}
   569  
   570  	if !reflect.DeepEqual(w.SliceVal.Interface(), data.Foo) {
   571  		t.Fatalf("bad: %#v", w.SliceVal.Interface())
   572  	}
   573  
   574  	if w.Count != 3 {
   575  		t.Fatalf("Bad count: %d", w.Count)
   576  	}
   577  }
   578  
   579  func TestWalk_SliceWithPtr(t *testing.T) {
   580  	w := new(TestSliceWalker)
   581  
   582  	// This is key, the panic only happened when the slice field was
   583  	// an interface!
   584  	type I interface{}
   585  
   586  	type S struct {
   587  		Foo []I
   588  	}
   589  
   590  	type Empty struct{}
   591  
   592  	data := &S{
   593  		Foo: []I{&Empty{}},
   594  	}
   595  
   596  	err := Walk(data, w)
   597  	if err != nil {
   598  		t.Fatalf("err: %s", err)
   599  	}
   600  
   601  	if !reflect.DeepEqual(w.SliceVal.Interface(), data.Foo) {
   602  		t.Fatalf("bad: %#v", w.SliceVal.Interface())
   603  	}
   604  
   605  	if w.Count != 1 {
   606  		t.Fatalf("Bad count: %d", w.Count)
   607  	}
   608  }
   609  
   610  func TestWalk_Array(t *testing.T) {
   611  	w := new(TestArrayWalker)
   612  
   613  	type S struct {
   614  		Foo [3]string
   615  	}
   616  
   617  	data := &S{
   618  		Foo: [3]string{"a", "b", "c"},
   619  	}
   620  
   621  	err := Walk(data, w)
   622  	if err != nil {
   623  		t.Fatalf("err: %s", err)
   624  	}
   625  
   626  	if !reflect.DeepEqual(w.ArrayVal.Interface(), data.Foo) {
   627  		t.Fatalf("bad: %#v", w.ArrayVal.Interface())
   628  	}
   629  
   630  	if w.Count != 3 {
   631  		t.Fatalf("Bad count: %d", w.Count)
   632  	}
   633  }
   634  
   635  func TestWalk_ArrayWithPtr(t *testing.T) {
   636  	w := new(TestArrayWalker)
   637  
   638  	// based on similar slice test
   639  	type I interface{}
   640  
   641  	type S struct {
   642  		Foo [1]I
   643  	}
   644  
   645  	type Empty struct{}
   646  
   647  	data := &S{
   648  		Foo: [1]I{&Empty{}},
   649  	}
   650  
   651  	err := Walk(data, w)
   652  	if err != nil {
   653  		t.Fatalf("err: %s", err)
   654  	}
   655  
   656  	if !reflect.DeepEqual(w.ArrayVal.Interface(), data.Foo) {
   657  		t.Fatalf("bad: %#v", w.ArrayVal.Interface())
   658  	}
   659  
   660  	if w.Count != 1 {
   661  		t.Fatalf("Bad count: %d", w.Count)
   662  	}
   663  }
   664  
   665  type testErr struct{}
   666  
   667  func (t *testErr) Error() string {
   668  	return "test error"
   669  }
   670  
   671  func TestWalk_Struct(t *testing.T) {
   672  	w := new(TestStructWalker)
   673  
   674  	// This makes sure we can also walk over pointer-to-pointers, and the ever
   675  	// so rare pointer-to-interface
   676  	type S struct {
   677  		Foo string
   678  		Bar *string
   679  		Baz **string
   680  		Err *error
   681  	}
   682  
   683  	bar := "ptr"
   684  	baz := &bar
   685  	e := error(&testErr{})
   686  
   687  	data := &S{
   688  		Foo: "foo",
   689  		Bar: &bar,
   690  		Baz: &baz,
   691  		Err: &e,
   692  	}
   693  
   694  	err := Walk(data, w)
   695  	if err != nil {
   696  		t.Fatalf("err: %s", err)
   697  	}
   698  
   699  	expected := []string{"Foo", "Bar", "Baz", "Err"}
   700  	if !reflect.DeepEqual(w.Fields, expected) {
   701  		t.Fatalf("bad: %#v", w.Fields)
   702  	}
   703  }
   704  
   705  // Very similar to above test but used to fail for #2, copied here for
   706  // regression testing
   707  func TestWalk_StructWithPtr(t *testing.T) {
   708  	w := new(TestStructWalker)
   709  
   710  	type S struct {
   711  		Foo string
   712  		Bar string
   713  		Baz *int
   714  	}
   715  
   716  	data := &S{
   717  		Foo: "foo",
   718  		Bar: "bar",
   719  	}
   720  
   721  	err := Walk(data, w)
   722  	if err != nil {
   723  		t.Fatalf("err: %s", err)
   724  	}
   725  
   726  	expected := []string{"Foo", "Bar", "Baz"}
   727  	if !reflect.DeepEqual(w.Fields, expected) {
   728  		t.Fatalf("bad: %#v", w.Fields)
   729  	}
   730  }
   731  
   732  type TestInterfaceMapWalker struct {
   733  	MapVal reflect.Value
   734  	Keys   map[string]bool
   735  	Values map[interface{}]bool
   736  }
   737  
   738  func (t *TestInterfaceMapWalker) Map(m reflect.Value) error {
   739  	t.MapVal = m
   740  	return nil
   741  }
   742  
   743  func (t *TestInterfaceMapWalker) MapElem(m, k, v reflect.Value) error {
   744  	if t.Keys == nil {
   745  		t.Keys = make(map[string]bool)
   746  		t.Values = make(map[interface{}]bool)
   747  	}
   748  
   749  	t.Keys[k.Interface().(string)] = true
   750  	t.Values[v.Interface()] = true
   751  	return nil
   752  }
   753  
   754  func TestWalk_MapWithPointers(t *testing.T) {
   755  	w := new(TestInterfaceMapWalker)
   756  
   757  	type S struct {
   758  		Foo map[string]interface{}
   759  	}
   760  
   761  	a := "a"
   762  	b := "b"
   763  
   764  	data := &S{
   765  		Foo: map[string]interface{}{
   766  			"foo": &a,
   767  			"bar": &b,
   768  			"baz": 11,
   769  			"zab": (*int)(nil),
   770  		},
   771  	}
   772  
   773  	err := Walk(data, w)
   774  	if err != nil {
   775  		t.Fatalf("err: %s", err)
   776  	}
   777  
   778  	if !reflect.DeepEqual(w.MapVal.Interface(), data.Foo) {
   779  		t.Fatalf("Bad: %#v", w.MapVal.Interface())
   780  	}
   781  
   782  	expectedK := map[string]bool{"foo": true, "bar": true, "baz": true, "zab": true}
   783  	if !reflect.DeepEqual(w.Keys, expectedK) {
   784  		t.Fatalf("Bad keys: %#v", w.Keys)
   785  	}
   786  
   787  	expectedV := map[interface{}]bool{&a: true, &b: true, 11: true, (*int)(nil): true}
   788  	if !reflect.DeepEqual(w.Values, expectedV) {
   789  		t.Fatalf("Bad values: %#v", w.Values)
   790  	}
   791  }
   792  
   793  type TestStructWalker_fieldSkip struct {
   794  	Skip   bool
   795  	Fields int
   796  }
   797  
   798  func (t *TestStructWalker_fieldSkip) Enter(l Location) error {
   799  	if l == StructField {
   800  		t.Fields++
   801  	}
   802  
   803  	return nil
   804  }
   805  
   806  func (t *TestStructWalker_fieldSkip) Exit(Location) error {
   807  	return nil
   808  }
   809  
   810  func (t *TestStructWalker_fieldSkip) Struct(v reflect.Value) error {
   811  	return nil
   812  }
   813  
   814  func (t *TestStructWalker_fieldSkip) StructField(sf reflect.StructField, v reflect.Value) error {
   815  	if t.Skip && sf.Name[0] == '_' {
   816  		return SkipEntry
   817  	}
   818  
   819  	return nil
   820  }
   821  
   822  func TestWalk_StructWithSkipEntry(t *testing.T) {
   823  	data := &struct {
   824  		Foo, _Bar int
   825  	}{
   826  		Foo:  1,
   827  		_Bar: 2,
   828  	}
   829  
   830  	{
   831  		var s TestStructWalker_fieldSkip
   832  		if err := Walk(data, &s); err != nil {
   833  			t.Fatalf("err: %s", err)
   834  		}
   835  
   836  		if s.Fields != 2 {
   837  			t.Fatalf("bad: %d", s.Fields)
   838  		}
   839  	}
   840  
   841  	{
   842  		var s TestStructWalker_fieldSkip
   843  		s.Skip = true
   844  		if err := Walk(data, &s); err != nil {
   845  			t.Fatalf("err: %s", err)
   846  		}
   847  
   848  		if s.Fields != 1 {
   849  			t.Fatalf("bad: %d", s.Fields)
   850  		}
   851  	}
   852  }
   853  
   854  type TestStructWalker_valueSkip struct {
   855  	Skip   bool
   856  	Fields int
   857  }
   858  
   859  func (t *TestStructWalker_valueSkip) Enter(l Location) error {
   860  	if l == StructField {
   861  		t.Fields++
   862  	}
   863  
   864  	return nil
   865  }
   866  
   867  func (t *TestStructWalker_valueSkip) Exit(Location) error {
   868  	return nil
   869  }
   870  
   871  func (t *TestStructWalker_valueSkip) Struct(v reflect.Value) error {
   872  	if t.Skip {
   873  		return SkipEntry
   874  	}
   875  
   876  	return nil
   877  }
   878  
   879  func (t *TestStructWalker_valueSkip) StructField(sf reflect.StructField, v reflect.Value) error {
   880  	return nil
   881  }
   882  
   883  func TestWalk_StructParentWithSkipEntry(t *testing.T) {
   884  	data := &struct {
   885  		Foo, _Bar int
   886  	}{
   887  		Foo:  1,
   888  		_Bar: 2,
   889  	}
   890  
   891  	{
   892  		var s TestStructWalker_valueSkip
   893  		if err := Walk(data, &s); err != nil {
   894  			t.Fatalf("err: %s", err)
   895  		}
   896  
   897  		if s.Fields != 2 {
   898  			t.Fatalf("bad: %d", s.Fields)
   899  		}
   900  	}
   901  
   902  	{
   903  		var s TestStructWalker_valueSkip
   904  		s.Skip = true
   905  		if err := Walk(data, &s); err != nil {
   906  			t.Fatalf("err: %s", err)
   907  		}
   908  
   909  		if s.Fields != 0 {
   910  			t.Fatalf("bad: %d", s.Fields)
   911  		}
   912  	}
   913  }
   914  

View as plain text