github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/dump/dumper_test.go (about)

     1  package dump
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  	"unsafe"
    10  
    11  	"github.com/gookit/color"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func newBufDumper(buf *bytes.Buffer) *Dumper {
    16  	return NewDumper(buf, 2)
    17  }
    18  
    19  var (
    20  	ints1 = []int{1, 2, 3, 4}
    21  	ints2 = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
    22  	user  = &struct {
    23  		id   string
    24  		Name string
    25  		Age  int
    26  	}{"ab12345", "inhere", 22}
    27  )
    28  
    29  func newStd() *Dumper {
    30  	return NewDumper(os.Stdout, 2)
    31  }
    32  
    33  func TestDumper_Fprint(t *testing.T) {
    34  	buffer := new(bytes.Buffer)
    35  	dumper := newStd()
    36  	dumper.WithoutColor()
    37  
    38  	dumper.Fprint(buffer, user)
    39  	str := buffer.String()
    40  	assert.Contains(t, str, "{ id string; Name string; Age int }")
    41  	assert.Contains(t, str, `id: string("ab12345"),`)
    42  	assert.Contains(t, str, `Name: string("inhere"),`)
    43  
    44  	dumper.ResetOptions()
    45  	dumper.Print(user)
    46  }
    47  
    48  func TestDump_Basic(t *testing.T) {
    49  	buffer := new(bytes.Buffer)
    50  	dumper := NewDumper(buffer, 2)
    51  
    52  	dumper.Dump(
    53  		nil,
    54  		// bool
    55  		false,
    56  		true,
    57  		// int(X)
    58  		12,
    59  		int8(12),
    60  		int16(12),
    61  		int32(12),
    62  		int64(12),
    63  		// uint(X)
    64  		uint(12),
    65  		uint8(12),
    66  		uint16(12),
    67  		uint32(12),
    68  		uint64(12),
    69  		// float
    70  		float32(3.1415926),
    71  		3.1415926, // float64
    72  		// string
    73  		"abc1234",
    74  		'a', // rune
    75  		byte('a'),
    76  	)
    77  
    78  	str := buffer.String()
    79  	str = color.ClearCode(str) // clear color codes.
    80  	assert.Contains(t, str, "github.com/bingoohuang/gg/pkg/dump.TestDump_Basic(dumper_test.go")
    81  	assert.Contains(t, str, "float64(3.1415926)")
    82  	assert.Contains(t, str, `string("abc1234")`)
    83  
    84  	// fmt.Println(str)
    85  	fmt.Println(buffer.String())
    86  }
    87  
    88  func TestDump_Ints(t *testing.T) {
    89  	buffer := new(bytes.Buffer)
    90  	dumper := NewDumper(buffer, 2)
    91  	dumper.WithoutColor()
    92  
    93  	// assert.Equal(t, 8, dumper.MoreLenNL)
    94  
    95  	dumper.Println(ints1)
    96  	str := buffer.String()
    97  	buffer.Reset()
    98  	assert.Contains(t, str, "[]int [ #len=4")
    99  	assert.Contains(t, str, "int(1),\n")
   100  
   101  	dumper.Print(ints2)
   102  	str = buffer.String()
   103  	buffer.Reset()
   104  	assert.Contains(t, str, "[]int [ #len=11")
   105  	assert.Contains(t, str, "int(1),\n")
   106  	assert.NotContains(t, str, "1, 2, 3, 4")
   107  	assert.NotContains(t, str, "[]int{1, 2, 3, 4}")
   108  
   109  	dumper.ResetOptions()
   110  	dumper.Dump(ints1)
   111  	dumper.Println(ints2)
   112  }
   113  
   114  func TestDump_Ptr(t *testing.T) {
   115  	buffer := new(bytes.Buffer)
   116  	dumper := NewDumper(buffer, 2)
   117  	// dumper.WithoutColor()
   118  
   119  	var s string
   120  
   121  	// refer string
   122  	dumper.Print(&s)
   123  	dumper.Print(s)
   124  
   125  	s = "abc23dddd"
   126  	dumper.Print(&s)
   127  	dumper.Print(s)
   128  
   129  	// refer struct
   130  	dumper.Println(user)
   131  	str := buffer.String()
   132  	str = color.ClearCode(str)
   133  	assert.Contains(t, str, "&struct")
   134  	assert.Contains(t, str, "Age: int(22),")
   135  	assert.Contains(t, str, `id: string("ab12345"),`)
   136  	assert.Contains(t, str, `Name: string("inhere"),`)
   137  
   138  	fmt.Println(buffer.String())
   139  	// Output:
   140  	// *struct { id string; Name string; Age int } {
   141  	//  id: string("ab12345"),
   142  	//  Name: string("inhere"),
   143  	//  Age: int(22),
   144  	// }
   145  }
   146  
   147  // code from https://stackoverflow.com/questions/42664837/how-to-access-unexported-struct-fields-in-golang
   148  func TestDumper_AccessCantExportedField(t *testing.T) {
   149  	type MyStruct struct {
   150  		// id string
   151  		id interface{}
   152  	}
   153  
   154  	myStruct := MyStruct{
   155  		id: "abc111222",
   156  	}
   157  
   158  	// - 下面的方式适用于: 结构体指针
   159  	rs := reflect.ValueOf(&myStruct).Elem()
   160  	rf := rs.Field(0)
   161  
   162  	fmt.Println(rf.CanInterface(), rf.String())
   163  	P(myStruct)
   164  
   165  	// rf can't be read or set.
   166  	rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
   167  	// Now rf can be read and set.
   168  
   169  	fmt.Println(rf.CanInterface(), rf.Interface())
   170  
   171  	// - 下面的方式适用于: 结构体值
   172  	rs = reflect.ValueOf(myStruct)
   173  	rs2 := reflect.New(rs.Type()).Elem()
   174  	rs2.Set(rs)
   175  	rf = rs2.Field(0)
   176  
   177  	fmt.Println(rf.CanInterface(), rf.String())
   178  
   179  	rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
   180  	// Now rf can be read.  Setting will succeed but only affects the temporary copy
   181  	fmt.Println(rf.CanInterface(), rf.String())
   182  }
   183  
   184  // code from https://stackoverflow.com/questions/42664837/how-to-access-unexported-struct-fields-in-golang
   185  func TestDumper_AccessCantExportedField1(t *testing.T) {
   186  	// init an nested struct
   187  	s1 := st1{st0{2}, 23, "inhere"}
   188  	myS1 := struct {
   189  		// cannotExport interface{} // ok
   190  		cannotExport st1 // ok
   191  		// CanExport interface{} ok
   192  		CanExport st1 // ok
   193  	}{
   194  		cannotExport: s1,
   195  		CanExport:    s1,
   196  	}
   197  
   198  	Println(myS1)
   199  }
   200  
   201  // ------------------------- map -------------------------
   202  
   203  func TestDump_Map(t *testing.T) {
   204  	m4 := map[string]interface{}{
   205  		"key1": 12,
   206  		"key2": "val1",
   207  		"key3": [][]int{
   208  			{23, 34},
   209  			{230, 340},
   210  		},
   211  		"key4": 3.14,
   212  		"key5": -34,
   213  		"key6": nil,
   214  		"key7": []int{23, 34},
   215  		"key8": map[string]interface{}{
   216  			"key8sub1": []int{23, 34},
   217  			"key8sub2": []string{"a", "b"},
   218  		},
   219  	}
   220  	Print(m4)
   221  }
   222  
   223  func TestMap_Simpled(t *testing.T) {
   224  	m1 := map[int]int{
   225  		23: 12,
   226  		24: 13,
   227  	}
   228  
   229  	m2 := map[string]int{
   230  		"key1": 12,
   231  		"key2": 13,
   232  	}
   233  
   234  	m3 := map[string]string{
   235  		"key1": "val1",
   236  		"key2": "val2",
   237  	}
   238  	P(m1, m2, m3)
   239  	/*
   240  		Output:
   241  		PRINT AT github.com/bingoohuang/gg/pkg/dump.TestMap_Simpled(dump_test.go:309)
   242  		map[int]int {
   243  		  24: int(13),
   244  		  23: int(12),
   245  		}
   246  		map[string]int {
   247  		  key1: int(12),
   248  		  key2: int(13),
   249  		}
   250  		map[string]string {
   251  		  key1: string("val1"),
   252  		  key2: string("val2"),
   253  		}
   254  
   255  	*/
   256  
   257  	m4 := map[string]interface{}{
   258  		"key1": 12,
   259  		"key2": "val1",
   260  		"key3": 34,
   261  		"key4": 3.14,
   262  		"key5": -34,
   263  		"key6": nil,
   264  	}
   265  	Print(m4)
   266  	/*
   267  		PRINT AT github.com/bingoohuang/gg/pkg/dump.TestMap_Simpled(dump_test.go:335)
   268  		map[string]interface {} {
   269  		  key4: float64(3.14),
   270  		  key5: int(-34),
   271  		  key6: <nil>,
   272  		  key1: int(12),
   273  		  key2: string("val1"),
   274  		  key3: int(34),
   275  		}
   276  	*/
   277  }
   278  
   279  func TestMap_InterfaceNested(t *testing.T) {
   280  	s1 := st1{st0{2}, 23, "inhere"}
   281  	m1 := map[string]interface{}{
   282  		"key1": 112,
   283  		"key2": uint(112),
   284  		"key3": int64(112),
   285  		"key4": 112.23,
   286  		"key5": nil,
   287  		"key6": 'b', // rune
   288  		"key7": byte('a'),
   289  		"st1":  s1,
   290  		"user": user,
   291  		"submap1": map[string]int{
   292  			"key1": 12,
   293  			"key2": 13,
   294  		},
   295  		"submap2": map[string]interface{}{
   296  			"key1": 12,
   297  			"key2": "abc",
   298  			"submap21": map[string]string{
   299  				"key1": "val1",
   300  				"key2": "val2",
   301  			},
   302  		},
   303  		"submap3": map[string]interface{}{
   304  			"key1": 12,
   305  			"key2": "abc",
   306  			"submap31": map[string]interface{}{
   307  				"key31": 12,
   308  				"key32": 13,
   309  				"user":  user,
   310  				"submap311": map[string]int{
   311  					"key1": 12,
   312  					"key2": 13,
   313  				},
   314  			},
   315  		},
   316  	}
   317  
   318  	newStd().WithOptions(func(opts *Options) {
   319  		opts.IndentChar = '-'
   320  	}).Dump(m1)
   321  }
   322  
   323  var myOpts = struct {
   324  	opt0 *int
   325  	opt1 bool
   326  	opt2 int
   327  	opt3 float64
   328  	opt4 string
   329  }{nil, true, 22, 34.45, "abc"}
   330  
   331  // ------------------------- map -------------------------
   332  
   333  type st0 struct {
   334  	Sex int
   335  }
   336  
   337  type st1 struct {
   338  	st0
   339  	Age  int
   340  	Name string
   341  }
   342  
   343  var s1 = st1{st0{2}, 23, "inhere"}
   344  
   345  func TestDump_Struct(t *testing.T) {
   346  }
   347  
   348  func TestStruct_WithNested(t *testing.T) {
   349  	// buffer := new(bytes.Buffer)
   350  	dumper := newStd()
   351  	dumper.IndentChar = '.'
   352  	dumper.Println(s1)
   353  	// OUT:
   354  	// PRINT AT github.com/bingoohuang/gg/pkg/dump.TestStruct_WithNested(dump_test.go:223)
   355  	// struct { dump.st0; Age int; Name string } {
   356  	//  st0: dump.st0 {
   357  	//    Sex: 2,
   358  	//  },
   359  	//  Age: 23,
   360  	//  Name: "inhere",
   361  	// }
   362  
   363  	type st2 struct {
   364  		st1
   365  		Github string
   366  	}
   367  
   368  	s2 := st2{st1: s1, Github: "https://github.com/inhere"}
   369  	dumper.IndentChar = ' '
   370  	dumper.Print(s2)
   371  
   372  	// Output:
   373  	// PRINT AT github.com/bingoohuang/gg/pkg/dump.TestStruct_WithNested(dump_test.go:257)
   374  	// dump.st2 {
   375  	//  st1: dump.st1 {
   376  	//    st0: dump.st0 {
   377  	//      Sex: int(2),
   378  	//    },
   379  	//    Age: int(23),
   380  	//    Name: string("inhere"),
   381  	//  },
   382  	//  Github: string("https://github.com/inhere"),
   383  	// }
   384  
   385  	s3 := struct {
   386  		st1
   387  		Github string
   388  	}{st1: s1, Github: "https://github.com/inhere"}
   389  
   390  	dumper.IndentChar = '.'
   391  	dumper.Print(s3)
   392  
   393  	// Output:
   394  	// PRINT AT github.com/bingoohuang/gg/pkg/dump.TestStruct_WithNested(dump_test.go:278)
   395  	// struct { dump.st1; Github string } {
   396  	//  st1: dump.st1 {
   397  	//    st0: dump.st0 {
   398  	//      Sex: int(2),
   399  	//    },
   400  	//    Age: int(23),
   401  	//    Name: string("inhere"),
   402  	//  },
   403  	//  Github: string("https://github.com/inhere"),
   404  	// }
   405  }