github.com/ergo-services/ergo@v1.999.224/etf/etf_test.go (about)

     1  package etf
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/ergo-services/ergo/lib"
    11  )
    12  
    13  func TestTermIntoStruct_Slice(t *testing.T) {
    14  	dest := []byte{}
    15  
    16  	tests := []struct {
    17  		want []byte
    18  		term Term
    19  	}{
    20  		{[]byte{1, 2, 3}, List{1, 2, 3}},
    21  	}
    22  
    23  	for _, tt := range tests {
    24  		if err := TermIntoStruct(tt.term, &dest); err != nil {
    25  			t.Errorf("%#v: conversion failed: %v", tt.term, err)
    26  		}
    27  
    28  		if !bytes.Equal(dest, tt.want) {
    29  			t.Errorf("%#v: got %v, want %v", tt.term, dest, tt.want)
    30  		}
    31  	}
    32  	tests1 := []struct {
    33  		want [][]float32
    34  		term Term
    35  	}{
    36  		{[][]float32{[]float32{1.23, 2.34, 3.45}, []float32{4.56, 5.67, 6.78}, []float32{7.89, 8.91, 9.12}}, List{List{1.23, 2.34, 3.45}, List{4.56, 5.67, 6.78}, List{7.89, 8.91, 9.12}}},
    37  	}
    38  	dest1 := [][]float32{}
    39  
    40  	for _, tt := range tests1 {
    41  		if err := TermIntoStruct(tt.term, &dest1); err != nil {
    42  			t.Errorf("%#v: conversion failed: %v", tt.term, err)
    43  		}
    44  
    45  		if !reflect.DeepEqual(dest1, tt.want) {
    46  			t.Errorf("%#v: got %v, want %v", tt.term, dest1, tt.want)
    47  		}
    48  	}
    49  }
    50  
    51  func TestTermIntoStruct_Array(t *testing.T) {
    52  	dest := [3]byte{}
    53  
    54  	tests := []struct {
    55  		want [3]byte
    56  		term Term
    57  	}{
    58  		{[...]byte{1, 2, 3}, List{1, 2, 3}},
    59  	}
    60  
    61  	for _, tt := range tests {
    62  		if err := TermIntoStruct(tt.term, &dest); err != nil {
    63  			t.Errorf("%#v: conversion failed: %v", tt.term, err)
    64  		}
    65  
    66  		if dest != tt.want {
    67  			t.Errorf("%#v: got %v, want %v", tt.term, dest, tt.want)
    68  		}
    69  	}
    70  
    71  	tests1 := []struct {
    72  		want [3][3]float64
    73  		term Term
    74  	}{
    75  		{[3][3]float64{[...]float64{1.23, 2.34, 3.45}, [...]float64{4.56, 5.67, 6.78}, [...]float64{7.89, 8.91, 9.12}}, List{List{1.23, 2.34, 3.45}, List{4.56, 5.67, 6.78}, List{7.89, 8.91, 9.12}}},
    76  	}
    77  	dest1 := [3][3]float64{}
    78  
    79  	for _, tt := range tests1 {
    80  		if err := TermIntoStruct(tt.term, &dest1); err != nil {
    81  			t.Errorf("%#v: conversion failed: %v", tt.term, err)
    82  		}
    83  
    84  		if !reflect.DeepEqual(dest1, tt.want) {
    85  			t.Errorf("%#v: got %v, want %v", tt.term, dest1, tt.want)
    86  		}
    87  	}
    88  }
    89  
    90  func TestTermIntoStruct_Struct(t *testing.T) {
    91  	type testAA struct {
    92  		A []bool
    93  		B uint32
    94  		C string
    95  	}
    96  
    97  	type testStruct struct {
    98  		AA testAA
    99  		BB float64
   100  		CC *testStruct
   101  	}
   102  	type testItem struct {
   103  		Want testStruct
   104  		Term Term
   105  	}
   106  
   107  	dest := testStruct{}
   108  	tests := []testItem{
   109  		testItem{
   110  			Want: testStruct{
   111  				AA: testAA{
   112  					A: []bool{true, false, false, true, false},
   113  					B: 8765,
   114  					C: "test value",
   115  				},
   116  				BB: 3.13,
   117  				CC: &testStruct{
   118  					BB: 4.14,
   119  					CC: &testStruct{
   120  						AA: testAA{
   121  							A: []bool{false, true},
   122  							B: 5,
   123  						},
   124  					},
   125  				},
   126  			},
   127  			Term: Tuple{ //testStruct
   128  				Tuple{ // AA testAA
   129  					List{true, false, false, true, false}, // A []bool
   130  					8765,                                  // B uint32
   131  					"test value",                          // C string
   132  				},
   133  				3.13, // BB float64
   134  				Tuple{ // CC *testStruct
   135  					Tuple{}, // AA testAA (empty)
   136  					4.14,    // BB float64
   137  					Tuple{ // CC *testStruct
   138  						Tuple{ // AA testAA
   139  							List{false, true}, // A []bool
   140  							5,                 // B uint32
   141  							// C string (empty)
   142  						},
   143  					},
   144  				},
   145  			},
   146  		},
   147  	}
   148  
   149  	for _, tt := range tests {
   150  		if err := TermIntoStruct(tt.Term, &dest); err != nil {
   151  			t.Errorf("%#v: conversion failed %v", tt.Term, err)
   152  		}
   153  
   154  		if !reflect.DeepEqual(dest, tt.Want) {
   155  			t.Errorf("%#v: got %#v, want %#v", tt.Term, dest, tt.Want)
   156  		}
   157  	}
   158  }
   159  
   160  func TestTermIntoStruct_Map(t *testing.T) {
   161  	type St struct {
   162  		A uint16
   163  		B float32
   164  	}
   165  	var destIS map[int]string
   166  	var destSI map[string]int
   167  	var destFlSt map[float64]St
   168  	var destSliceSI []map[bool][]int8
   169  
   170  	wantIS := map[int]string{
   171  		888: "hello",
   172  		777: "world",
   173  	}
   174  	termIS := Map{
   175  		888: "hello",
   176  		777: Atom("world"),
   177  	}
   178  	if err := TermIntoStruct(termIS, &destIS); err != nil {
   179  		t.Errorf("%#v: conversion failed %v", termIS, err)
   180  	}
   181  
   182  	if !reflect.DeepEqual(destIS, wantIS) {
   183  		t.Errorf("%#v: got %#v, want %#v", termIS, destIS, wantIS)
   184  	}
   185  
   186  	wantSI := map[string]int{
   187  		"hello": 888,
   188  		"world": 777,
   189  	}
   190  	termSI := Map{
   191  		"hello":       888,
   192  		Atom("world"): 777,
   193  	}
   194  	if err := TermIntoStruct(termSI, &destSI); err != nil {
   195  		t.Errorf("%#v: conversion failed %v", termSI, err)
   196  	}
   197  
   198  	if !reflect.DeepEqual(destSI, wantSI) {
   199  		t.Errorf("%#v: got %#v, want %#v", termSI, destSI, wantSI)
   200  	}
   201  
   202  	wantFlSt := map[float64]St{
   203  		3.45: St{67, 8.91},
   204  		7.65: St{43, 2.19},
   205  	}
   206  	termFlSt := Map{
   207  		3.45: Tuple{67, 8.91},
   208  		7.65: Tuple{43, 2.19},
   209  	}
   210  	if err := TermIntoStruct(termFlSt, &destFlSt); err != nil {
   211  		t.Errorf("%#v: conversion failed %v", termFlSt, err)
   212  	}
   213  
   214  	if !reflect.DeepEqual(destFlSt, wantFlSt) {
   215  		t.Errorf("%#v: got %#v, want %#v", termFlSt, destFlSt, wantFlSt)
   216  	}
   217  
   218  	wantSliceSI := []map[bool][]int8{
   219  		map[bool][]int8{
   220  			true:  []int8{1, 2, 3, 4, 5},
   221  			false: []int8{11, 22, 33, 44, 55},
   222  		},
   223  		map[bool][]int8{
   224  			true:  []int8{21, 22, 23, 24, 25},
   225  			false: []int8{-11, -22, -33, -44, -55},
   226  		},
   227  	}
   228  	termSliceSI := List{
   229  		Map{
   230  			true:  List{1, 2, 3, 4, 5},
   231  			false: List{11, 22, 33, 44, 55},
   232  		},
   233  		Map{
   234  			true:  List{21, 22, 23, 24, 25},
   235  			false: List{-11, -22, -33, -44, -55},
   236  		},
   237  	}
   238  	if err := TermIntoStruct(termSliceSI, &destSliceSI); err != nil {
   239  		t.Errorf("%#v: conversion failed %v", termSliceSI, err)
   240  	}
   241  
   242  	if !reflect.DeepEqual(destSliceSI, wantSliceSI) {
   243  		t.Errorf("%#v: got %#v, want %#v", termSliceSI, destSliceSI, wantSliceSI)
   244  	}
   245  }
   246  
   247  func TestTermMapIntoStruct_Struct(t *testing.T) {
   248  	type testStruct struct {
   249  		A []bool `etf:"a"`
   250  		B uint32 `etf:"b"`
   251  		C string `etf:"c"`
   252  	}
   253  
   254  	dest := testStruct{}
   255  
   256  	want := testStruct{
   257  		A: []bool{false, true, true},
   258  		B: 3233,
   259  		C: "hello world",
   260  	}
   261  
   262  	term := Map{
   263  		Atom("a"): List{false, true, true},
   264  		"b":       3233,
   265  		Atom("c"): "hello world",
   266  	}
   267  
   268  	if err := TermIntoStruct(term, &dest); err != nil {
   269  		t.Errorf("%#v: conversion failed %v", term, err)
   270  	}
   271  
   272  	if !reflect.DeepEqual(dest, want) {
   273  		t.Errorf("%#v: got %#v, want %#v", term, dest, want)
   274  	}
   275  
   276  }
   277  func TestTermMapIntoMap(t *testing.T) {
   278  	type testMap map[string]int
   279  
   280  	var dest testMap
   281  
   282  	want := testMap{
   283  		"a": 123,
   284  		"b": 456,
   285  		"c": 789,
   286  	}
   287  
   288  	term := Map{
   289  		Atom("a"): 123,
   290  		"b":       456,
   291  		Atom("c"): 789,
   292  	}
   293  
   294  	if err := TermIntoStruct(term, &dest); err != nil {
   295  		t.Errorf("%#v: conversion failed %v", term, err)
   296  	}
   297  
   298  	if !reflect.DeepEqual(dest, want) {
   299  		t.Errorf("%#v: got %#v, want %#v", term, dest, want)
   300  	}
   301  
   302  }
   303  
   304  func TestTermProplistIntoStruct(t *testing.T) {
   305  	type testStruct struct {
   306  		A []bool `etf:"a"`
   307  		B uint32 `etf:"b"`
   308  		C string `etf:"c"`
   309  	}
   310  
   311  	dest := testStruct{}
   312  
   313  	want := testStruct{
   314  		A: []bool{false, true, true},
   315  		B: 3233,
   316  		C: "hello world",
   317  	}
   318  	termList := List{
   319  		Tuple{Atom("a"), List{false, true, true}},
   320  		Tuple{"b", 3233},
   321  		Tuple{Atom("c"), "hello world"},
   322  	}
   323  
   324  	if err := TermProplistIntoStruct(termList, &dest); err != nil {
   325  		t.Errorf("%#v: conversion failed %v", termList, err)
   326  	}
   327  
   328  	if !reflect.DeepEqual(dest, want) {
   329  		t.Errorf("%#v: got %#v, want %#v", termList, dest, want)
   330  	}
   331  
   332  	termSliceProplistElements := []ProplistElement{
   333  		ProplistElement{Atom("a"), List{false, true, true}},
   334  		ProplistElement{"b", 3233},
   335  		ProplistElement{Atom("c"), "hello world"},
   336  	}
   337  
   338  	if err := TermProplistIntoStruct(termSliceProplistElements, &dest); err != nil {
   339  		t.Errorf("%#v: conversion failed %v", termList, err)
   340  	}
   341  
   342  	if !reflect.DeepEqual(dest, want) {
   343  		t.Errorf("%#v: got %#v, want %#v", termSliceProplistElements, dest, want)
   344  	}
   345  }
   346  
   347  func TestTermIntoStructCharlistString(t *testing.T) {
   348  	b := lib.TakeBuffer()
   349  	defer lib.ReleaseBuffer(b)
   350  
   351  	type Nested struct {
   352  		NestedKey1 String
   353  		NestedKey2 map[string]*Charlist `etf:"field"`
   354  	}
   355  	type StructCharlistString struct {
   356  		Key1 string
   357  		Key2 []*Charlist `etf:"custom_field_name"`
   358  		Key3 *Nested
   359  		Key4 [][]*Charlist
   360  	}
   361  
   362  	nestedMap := make(map[string]*Charlist)
   363  	value1 := Charlist("Hello World! 你好世界! Привет Мир! 🚀")
   364  	value11 := String("Hello World! 你好世界! Привет Мир! 🚀")
   365  	nestedMap["map_key"] = &value1
   366  
   367  	nested := Nested{
   368  		NestedKey1: value11,
   369  		NestedKey2: nestedMap,
   370  	}
   371  
   372  	value2 := Charlist("你好世界! 🚀")
   373  	value3 := Charlist("Привет Мир! 🚀")
   374  	value4 := Charlist("Hello World! 🚀")
   375  	term := StructCharlistString{
   376  		Key1: "Hello World!",
   377  		Key2: []*Charlist{&value2, &value3, &value4},
   378  		Key3: &nested,
   379  		Key4: [][]*Charlist{[]*Charlist{&value2, &value3, &value4}, []*Charlist{&value2, &value3, &value4}},
   380  	}
   381  	err := Encode(term, b, EncodeOptions{})
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  
   386  	term_Term, _, err := Decode(b.B, []Atom{}, DecodeOptions{})
   387  	if err != nil {
   388  		t.Fatal(err)
   389  	}
   390  
   391  	term_dest := StructCharlistString{}
   392  	if err := TermIntoStruct(term_Term, &term_dest); err != nil {
   393  		t.Fatal(err)
   394  	}
   395  
   396  	if !reflect.DeepEqual(term, term_dest) {
   397  		t.Fatal("result != expected")
   398  	}
   399  }
   400  
   401  func TestCharlistToString(t *testing.T) {
   402  	l := List{72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 32, 20320, 22909, 19990, 30028, 33, 32, 1055, 1088, 1080, 1074, 1077, 1090, 32, 1052, 1080, 1088, 33, 32, 128640}
   403  	s, err := convertCharlistToString(l)
   404  	if err != nil {
   405  		t.Fatal(err)
   406  	}
   407  	expected := "Hello World! 你好世界! Привет Мир! 🚀"
   408  	if s != expected {
   409  		t.Error("want", expected)
   410  		t.Error("got", s)
   411  		t.Fatal("incorrect result")
   412  	}
   413  
   414  }
   415  
   416  func TestEncodeDecodePid(t *testing.T) {
   417  	b := lib.TakeBuffer()
   418  	defer lib.ReleaseBuffer(b)
   419  
   420  	pidIn := Pid{Node: "erl-demo@127.0.0.1", ID: 32767, Creation: 2}
   421  
   422  	err := Encode(pidIn, b, EncodeOptions{})
   423  	if err != nil {
   424  		t.Fatal(err)
   425  	}
   426  
   427  	term, _, err := Decode(b.B, []Atom{}, DecodeOptions{})
   428  	pidOut, ok := term.(Pid)
   429  	if !ok {
   430  		t.Fatal("incorrect result")
   431  	}
   432  
   433  	if pidIn != pidOut {
   434  		t.Error("want", pidIn)
   435  		t.Error("got", pidOut)
   436  		t.Fatal("incorrect result")
   437  	}
   438  
   439  	// enable BigCreation
   440  	b.Reset()
   441  	encodeOptions := EncodeOptions{
   442  		FlagBigCreation: true,
   443  	}
   444  	err = Encode(pidIn, b, encodeOptions)
   445  	if err != nil {
   446  		t.Fatal(err)
   447  	}
   448  
   449  	decodeOptions := DecodeOptions{}
   450  	term, _, err = Decode(b.B, []Atom{}, decodeOptions)
   451  	pidOut, ok = term.(Pid)
   452  	if !ok {
   453  		t.Fatal("incorrect result")
   454  	}
   455  
   456  	if pidIn != pidOut {
   457  		t.Error("want", pidIn)
   458  		t.Error("got", pidOut)
   459  		t.Fatal("incorrect result")
   460  	}
   461  
   462  	// enable FlagBigPidRef
   463  	b.Reset()
   464  	encodeOptions = EncodeOptions{
   465  		FlagBigPidRef: true,
   466  	}
   467  	err = Encode(pidIn, b, encodeOptions)
   468  	if err != nil {
   469  		t.Fatal(err)
   470  	}
   471  
   472  	decodeOptions = DecodeOptions{
   473  		FlagBigPidRef: true,
   474  	}
   475  	term, _, err = Decode(b.B, []Atom{}, decodeOptions)
   476  	pidOut, ok = term.(Pid)
   477  	if !ok {
   478  		t.Fatal("incorrect result")
   479  	}
   480  
   481  	if pidIn != pidOut {
   482  		t.Error("want", pidIn)
   483  		t.Error("got", pidOut)
   484  		t.Fatal("incorrect result")
   485  	}
   486  
   487  	// enable BigCreation and FlagBigPidRef
   488  	b.Reset()
   489  	encodeOptions = EncodeOptions{
   490  		FlagBigPidRef:   true,
   491  		FlagBigCreation: true,
   492  	}
   493  	err = Encode(pidIn, b, encodeOptions)
   494  	if err != nil {
   495  		t.Fatal(err)
   496  	}
   497  
   498  	decodeOptions = DecodeOptions{
   499  		FlagBigPidRef: true,
   500  	}
   501  	term, _, err = Decode(b.B, []Atom{}, decodeOptions)
   502  	pidOut, ok = term.(Pid)
   503  	if !ok {
   504  		t.Fatal("incorrect result")
   505  	}
   506  
   507  	if pidIn != pidOut {
   508  		t.Error("want", pidIn)
   509  		t.Error("got", pidOut)
   510  		t.Fatal("incorrect result")
   511  	}
   512  }
   513  
   514  type myTime struct {
   515  	Time time.Time
   516  }
   517  
   518  func (m myTime) MarshalETF() ([]byte, error) {
   519  	s := fmt.Sprintf("%s", m.Time.Format(time.RFC3339))
   520  	return []byte(s), nil
   521  }
   522  
   523  func (m *myTime) UnmarshalETF(b []byte) error {
   524  	t, e := time.Parse(
   525  		time.RFC3339, string(b))
   526  	m.Time = t
   527  	return e
   528  }
   529  
   530  func TestTermIntoStructUnmarshal(t *testing.T) {
   531  	b := lib.TakeBuffer()
   532  	defer lib.ReleaseBuffer(b)
   533  
   534  	var src, dest myTime
   535  
   536  	now := time.Now()
   537  	s := fmt.Sprintf("%s", now.Format(time.RFC3339))
   538  	now, _ = time.Parse(time.RFC3339, s)
   539  
   540  	src.Time = now
   541  	err := Encode(src, b, EncodeOptions{})
   542  	if err != nil {
   543  		t.Fatal(err)
   544  	}
   545  	term, _, err := Decode(b.B, []Atom{}, DecodeOptions{})
   546  	if err != nil {
   547  		t.Fatal(err)
   548  	}
   549  
   550  	if err := TermIntoStruct(term, &dest); err != nil {
   551  		t.Errorf("%#v: conversion failed %v", term, err)
   552  	}
   553  
   554  	if src != dest {
   555  		t.Fatal("wrong value")
   556  	}
   557  
   558  	type aaa struct {
   559  		A1 myTime
   560  		A2 *myTime
   561  	}
   562  
   563  	var src1 aaa
   564  	var dst1 aaa
   565  
   566  	src1.A1.Time = now
   567  	src1.A2 = &myTime{now}
   568  
   569  	b.Reset()
   570  
   571  	err = Encode(src1, b, EncodeOptions{})
   572  	if err != nil {
   573  		t.Fatal(err)
   574  	}
   575  	term, _, err = Decode(b.B, []Atom{}, DecodeOptions{})
   576  	if err != nil {
   577  		t.Fatal(err)
   578  	}
   579  
   580  	if err = TermIntoStruct(term, &dst1); err != nil {
   581  		t.Errorf("%#v: conversion failed %v", term, err)
   582  	}
   583  	if !reflect.DeepEqual(src1, dst1) {
   584  		t.Errorf("got %v, want %v", dst1, src1)
   585  	}
   586  }
   587  
   588  func TestRegisterSlice(t *testing.T) {
   589  	type sliceString []string
   590  	type sliceInt []int
   591  	type sliceInt8 []int8
   592  	type sliceInt16 []int16
   593  	type sliceInt32 []int32
   594  	type sliceInt64 []int64
   595  	type sliceUint []uint
   596  	type sliceUint8 []uint8
   597  	type sliceUint16 []uint16
   598  	type sliceUint32 []uint32
   599  	type sliceUint64 []uint64
   600  	type sliceFloat32 []float32
   601  	type sliceFloat64 []float64
   602  
   603  	type allInOneSlices struct {
   604  		A sliceString
   605  		B sliceInt
   606  		C sliceInt8
   607  		D sliceInt16
   608  		E sliceInt32
   609  		F sliceInt64
   610  		G sliceUint
   611  		H sliceUint8
   612  		I sliceUint16
   613  		K sliceUint32
   614  		L sliceUint64
   615  		M sliceFloat32
   616  		O sliceFloat64
   617  	}
   618  	types := []interface{}{
   619  		sliceString{},
   620  		sliceInt{},
   621  		sliceInt8{},
   622  		sliceInt16{},
   623  		sliceInt32{},
   624  		sliceInt64{},
   625  		sliceUint{},
   626  		sliceUint8{},
   627  		sliceUint16{},
   628  		sliceUint32{},
   629  		sliceUint64{},
   630  		sliceFloat32{},
   631  		sliceFloat64{},
   632  		allInOneSlices{},
   633  	}
   634  	if err := registerTypes(types); err != nil {
   635  		t.Fatal(err)
   636  	}
   637  
   638  	src := allInOneSlices{
   639  		A: sliceString{"Hello", "World"},
   640  		B: sliceInt{-1, 2, -3, 4, -5},
   641  		C: sliceInt8{-1, 2, -3, 4, -5},
   642  		D: sliceInt16{-1, 2, -3, 4, -5},
   643  		E: sliceInt32{-1, 2, -3, 4, -5},
   644  		F: sliceInt64{-1, 2, -3, 4, -5},
   645  		G: sliceUint{1, 2, 3, 4, 5},
   646  		H: sliceUint8{1, 2, 3, 4, 5},
   647  		I: sliceUint16{1, 2, 3, 4, 5},
   648  		K: sliceUint32{1, 2, 3, 4, 5},
   649  		L: sliceUint64{1, 2, 3, 4, 5},
   650  		M: sliceFloat32{1.1, -2.2, 3.3, -4.4, 5.5},
   651  		O: sliceFloat64{1.1, -2.2, 3.3, -4.4, 5.5},
   652  	}
   653  
   654  	buf := lib.TakeBuffer()
   655  	defer lib.ReleaseBuffer(buf)
   656  
   657  	encodeOptions := EncodeOptions{
   658  		FlagBigPidRef:   true,
   659  		FlagBigCreation: true,
   660  	}
   661  	if err := Encode(src, buf, encodeOptions); err != nil {
   662  		t.Fatal(err)
   663  	}
   664  	decodeOptions := DecodeOptions{
   665  		FlagBigPidRef: true,
   666  	}
   667  	dst, _, err := Decode(buf.B, []Atom{}, decodeOptions)
   668  	if err != nil {
   669  		t.Fatal(err)
   670  	}
   671  
   672  	if _, ok := dst.(allInOneSlices); !ok {
   673  		t.Fatalf("wrong term result: %#v\n", dst)
   674  	}
   675  
   676  	if !reflect.DeepEqual(src, dst) {
   677  		t.Errorf("got:\n%#v\n\nwant:\n%#v\n", dst, src)
   678  	}
   679  }
   680  
   681  func TestRegisterMap(t *testing.T) {
   682  	type mapIntString map[int]string
   683  	type mapStringInt map[string]int
   684  	type mapInt8Int map[int8]int
   685  	type mapFloat32Int32 map[float32]int32
   686  	type mapFloat64Int32 map[float64]int32
   687  	type mapInt32Float32 map[int32]float32
   688  	type mapInt32Float64 map[int32]float64
   689  
   690  	type allInOne struct {
   691  		A mapIntString
   692  		B mapStringInt
   693  		C mapInt8Int
   694  		D mapFloat32Int32
   695  		E mapFloat64Int32
   696  		F mapInt32Float32
   697  		G mapInt32Float64
   698  	}
   699  
   700  	types := []interface{}{
   701  		mapIntString{},
   702  		mapStringInt{},
   703  		mapInt8Int{},
   704  		mapFloat32Int32{},
   705  		mapFloat64Int32{},
   706  		mapInt32Float32{},
   707  		mapInt32Float64{},
   708  		allInOne{},
   709  	}
   710  	if err := registerTypes(types); err != nil {
   711  		t.Fatal(err)
   712  	}
   713  
   714  	src := allInOne{
   715  		A: make(mapIntString),
   716  		B: make(mapStringInt),
   717  		C: make(mapInt8Int),
   718  		D: make(mapFloat32Int32),
   719  		E: make(mapFloat64Int32),
   720  		F: make(mapInt32Float32),
   721  		G: make(mapInt32Float64),
   722  	}
   723  
   724  	src.A[1] = "Hello"
   725  	src.B["Hello"] = 1
   726  	src.C[1] = 1
   727  	src.D[3.14] = 1
   728  	src.E[3.15] = 1
   729  	src.F[1] = 3.15
   730  	src.G[1] = 3.15
   731  
   732  	buf := lib.TakeBuffer()
   733  	defer lib.ReleaseBuffer(buf)
   734  
   735  	encodeOptions := EncodeOptions{
   736  		FlagBigPidRef:   true,
   737  		FlagBigCreation: true,
   738  	}
   739  	if err := Encode(src, buf, encodeOptions); err != nil {
   740  		t.Fatal(err)
   741  	}
   742  	decodeOptions := DecodeOptions{
   743  		FlagBigPidRef: true,
   744  	}
   745  	dst, _, err := Decode(buf.B, []Atom{}, decodeOptions)
   746  	if err != nil {
   747  		t.Fatal(err)
   748  	}
   749  
   750  	if _, ok := dst.(allInOne); !ok {
   751  		t.Fatalf("wrong term result: %#v\n", dst)
   752  	}
   753  
   754  	if !reflect.DeepEqual(src, dst) {
   755  		t.Errorf("got:\n%#v\n\nwant:\n%#v\n", dst, src)
   756  	}
   757  
   758  }
   759  
   760  func TestRegisterType(t *testing.T) {
   761  	type ccc []string
   762  	type ddd [3]bool
   763  	type aaa struct {
   764  		A   string
   765  		B   int
   766  		B8  int8
   767  		B16 int16
   768  		B32 int32
   769  		B64 int64
   770  
   771  		BU   uint
   772  		BU8  uint8
   773  		BU16 uint16
   774  		BU32 uint32
   775  		BU64 uint64
   776  
   777  		C   float32
   778  		C64 float64
   779  		D   ddd
   780  
   781  		T1 Pid
   782  		T2 Ref
   783  		T3 Alias
   784  	}
   785  	type bbb map[aaa]ccc
   786  
   787  	src := bbb{
   788  		aaa{
   789  			A:    "aa",
   790  			B:    -11,
   791  			B8:   -18,
   792  			B16:  -1116,
   793  			B32:  -1132,
   794  			B64:  -1164,
   795  			BU:   0xb,
   796  			BU8:  0x12,
   797  			BU16: 0x45c,
   798  			BU32: 0x46c,
   799  			BU64: 0x48c,
   800  			C:    -11.22,
   801  			C64:  1164.22,
   802  			D:    ddd{true, false, false},
   803  			T1:   Pid{Node: Atom("nodepid11"), ID: 123, Creation: 456},
   804  			T2:   Ref{Node: Atom("noderef11"), Creation: 123, ID: [5]uint32{4, 5, 6, 0, 0}},
   805  			T3:   Alias{Node: Atom("nodealias11"), Creation: 123, ID: [5]uint32{4, 5, 6, 0, 0}},
   806  		}: ccc{"a1", "a2", "a3"},
   807  		aaa{
   808  			A:    "bb",
   809  			B:    -22,
   810  			B8:   -28,
   811  			B16:  -2216,
   812  			B32:  -2232,
   813  			B64:  -2264,
   814  			BU:   0x16,
   815  			BU8:  0x1c,
   816  			BU16: 0x8a8,
   817  			BU32: 0x8b8,
   818  			BU64: 0x8d8,
   819  			C:    -22.22,
   820  			C64:  2264.22,
   821  			D:    ddd{false, true, false},
   822  			T1:   Pid{Node: Atom("nodepid22"), ID: 123, Creation: 456},
   823  			T2:   Ref{Node: Atom("noderef22"), Creation: 123, ID: [5]uint32{4, 5, 6, 0, 0}},
   824  			T3:   Alias{Node: Atom("nodealias22"), Creation: 123, ID: [5]uint32{4, 5, 6, 0, 0}},
   825  		}: ccc{"b1", "b2", "b3"},
   826  		aaa{
   827  			A:    "cc",
   828  			B:    -33,
   829  			B8:   -38,
   830  			B16:  -3316,
   831  			B32:  -3332,
   832  			B64:  -3364,
   833  			BU:   0x21,
   834  			BU8:  0x26,
   835  			BU16: 0xcf4,
   836  			BU32: 0xd04,
   837  			BU64: 0xd24,
   838  			C:    -33.22,
   839  			C64:  3364.22,
   840  			D:    ddd{false, false, true},
   841  			T1:   Pid{Node: Atom("nodepid33"), ID: 123, Creation: 456},
   842  			T2:   Ref{Node: Atom("noderef33"), Creation: 123, ID: [5]uint32{4, 5, 6, 0, 0}},
   843  			T3:   Alias{Node: Atom("nodealias33"), Creation: 123, ID: [5]uint32{4, 5, 6, 0, 0}},
   844  		}: ccc{}, //test empty list
   845  	}
   846  
   847  	buf := lib.TakeBuffer()
   848  	defer lib.ReleaseBuffer(buf)
   849  
   850  	if _, err := RegisterType(Pid{}, RegisterTypeOptions{Strict: true}); err == nil {
   851  		t.Fatal("shouldn't be registered")
   852  	}
   853  	if _, err := RegisterType(Ref{}, RegisterTypeOptions{Strict: true}); err == nil {
   854  		t.Fatal("shouldn't be registered")
   855  	}
   856  	if _, err := RegisterType(Alias{}, RegisterTypeOptions{Strict: true}); err == nil {
   857  		t.Fatal("shouldn't be registered")
   858  	}
   859  
   860  	types := []interface{}{
   861  		ddd{},
   862  		aaa{},
   863  		ccc{},
   864  		bbb{},
   865  	}
   866  	if err := registerTypes(types); err != nil {
   867  		t.Fatal(err)
   868  	}
   869  
   870  	encodeOptions := EncodeOptions{
   871  		FlagBigPidRef:   true,
   872  		FlagBigCreation: true,
   873  	}
   874  	if err := Encode(src, buf, encodeOptions); err != nil {
   875  		t.Fatal(err)
   876  	}
   877  	decodeOptions := DecodeOptions{
   878  		FlagBigPidRef: true,
   879  	}
   880  	dst, _, err := Decode(buf.B, []Atom{}, decodeOptions)
   881  	if err != nil {
   882  		t.Fatal(err)
   883  	}
   884  
   885  	if _, ok := dst.(bbb); !ok {
   886  		t.Fatal("wrong term result")
   887  	}
   888  
   889  	if !reflect.DeepEqual(src, dst) {
   890  		t.Errorf("got:\n%#v\n\nwant:\n%#v\n", dst, src)
   891  	}
   892  }
   893  
   894  func registerTypes(types []interface{}) error {
   895  	rtOpts := RegisterTypeOptions{Strict: true}
   896  
   897  	for _, t := range types {
   898  		if _, err := RegisterType(t, rtOpts); err != nil && err != lib.ErrTaken {
   899  			return err
   900  		}
   901  	}
   902  	return nil
   903  }