github.com/stellar/go-xdr@v0.0.0-20231122183749-b53fb00bcac2/xdr2/encode_test.go (about)

     1  /*
     2   * Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
     3   *
     4   * Permission to use, copy, modify, and distribute this software for any
     5   * purpose with or without fee is hereby granted, provided that the above
     6   * copyright notice and this permission notice appear in all copies.
     7   *
     8   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     9   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    10   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    11   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    12   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    13   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    14   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    15   */
    16  
    17  package xdr_test
    18  
    19  import (
    20  	"fmt"
    21  	"math"
    22  	"reflect"
    23  	"testing"
    24  	"time"
    25  
    26  	. "github.com/stellar/go-xdr/xdr2"
    27  )
    28  
    29  // testExpectedMRet is a convenience method to test an expected number of bytes
    30  // written and error for a marshal.
    31  func testExpectedMRet(t *testing.T, name string, n, wantN int, err, wantErr error) bool {
    32  	// First ensure the number of bytes written is the expected value.  The
    33  	// bytes read should be accurate even when an error occurs.
    34  	if n != wantN {
    35  		t.Errorf("%s: unexpected num bytes written - got: %v want: %v\n",
    36  			name, n, wantN)
    37  		return false
    38  	}
    39  
    40  	// Next check for the expected error.
    41  	if reflect.TypeOf(err) != reflect.TypeOf(wantErr) {
    42  		t.Errorf("%s: failed to detect error - got: %v <%[2]T> want: %T",
    43  			name, err, wantErr)
    44  		return false
    45  	}
    46  	if rerr, ok := err.(*MarshalError); ok {
    47  		if werr, ok := wantErr.(*MarshalError); ok {
    48  			if rerr.ErrorCode != werr.ErrorCode {
    49  				t.Errorf("%s: failed to detect error code - "+
    50  					"got: %v want: %v", name,
    51  					rerr.ErrorCode, werr.ErrorCode)
    52  				return false
    53  			}
    54  		}
    55  	}
    56  
    57  	return true
    58  }
    59  
    60  // TestMarshal ensures the Marshal function works properly with all types.
    61  func TestMarshal(t *testing.T) {
    62  	// Variables for various unsupported Marshal types.
    63  	var nilInterface interface{}
    64  	var testChan chan int
    65  	var testFunc func()
    66  	var testComplex64 complex64
    67  	var testComplex128 complex128
    68  
    69  	// testInterface is used to test Marshal with values nested in an
    70  	// interface.
    71  	testInterface := interface{}(17)
    72  
    73  	// structMarshalTestIn is input data for the big struct test of all
    74  	// supported types.
    75  	structMarshalTestIn := allTypesTest{
    76  		127,                                // A
    77  		255,                                // B
    78  		32767,                              // C
    79  		65535,                              // D
    80  		2147483647,                         // E
    81  		4294967295,                         // F
    82  		9223372036854775807,                // G
    83  		18446744073709551615,               // H
    84  		true,                               // I
    85  		3.14,                               // J
    86  		3.141592653589793,                  // K
    87  		"xdr",                              // L
    88  		[]byte{1, 2, 3, 4},                 // M
    89  		[3]byte{1, 2, 3},                   // N
    90  		[]int16{512, 1024, 2048},           // O
    91  		[2]subTest{{"one", 1}, {"two", 2}}, // P
    92  		&subTest{"bar", 3},                 // Q
    93  		map[string]uint32{"map1": 1},       // R
    94  		time.Unix(1396581888, 0).UTC(),     // S
    95  	}
    96  
    97  	// structMarshalTestWant is the expected output after marshalling
    98  	// structMarshalTestIn.
    99  	structMarshalTestWant := []byte{
   100  		0x00, 0x00, 0x00, 0x7F, // A
   101  		0x00, 0x00, 0x00, 0xFF, // B
   102  		0x00, 0x00, 0x7F, 0xFF, // C
   103  		0x00, 0x00, 0xFF, 0xFF, // D
   104  		0x7F, 0xFF, 0xFF, 0xFF, // E
   105  		0xFF, 0xFF, 0xFF, 0xFF, // F
   106  		0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // G
   107  		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // H
   108  		0x00, 0x00, 0x00, 0x01, // I
   109  		0x40, 0x48, 0xF5, 0xC3, // J
   110  		0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, // K
   111  		0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00, // L
   112  		0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04, // M
   113  		0x01, 0x02, 0x03, 0x00, // N
   114  		0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00,
   115  		0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, // O
   116  		0x00, 0x00, 0x00, 0x03, 0x6F, 0x6E, 0x65, 0x00, // P[0].A
   117  		0x00, 0x00, 0x00, 0x01, // P[0].B
   118  		0x00, 0x00, 0x00, 0x03, 0x74, 0x77, 0x6F, 0x00, // P[1].A
   119  		0x00, 0x00, 0x00, 0x02, // P[1].B
   120  		0x00, 0x00, 0x00, 0x03, 0x62, 0x61, 0x72, 0x00, // Q.A
   121  		0x00, 0x00, 0x00, 0x03, // Q.B
   122  		0x00, 0x00, 0x00, 0x01, // R length
   123  		0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31, // R key map1
   124  		0x00, 0x00, 0x00, 0x01, // R value map1
   125  		0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34,
   126  		0x2d, 0x30, 0x34, 0x2d, 0x30, 0x34, 0x54, 0x30,
   127  		0x33, 0x3a, 0x32, 0x34, 0x3a, 0x34, 0x38, 0x5a, // S
   128  	}
   129  
   130  	tests := []struct {
   131  		in        interface{} // input value
   132  		wantBytes []byte      // expected bytes
   133  		wantN     int         // expected/max number of bytes written
   134  		err       error       // expected error
   135  	}{
   136  		// interface
   137  		{testInterface, []byte{0x00, 0x00, 0x00, 0x11}, 4, nil},
   138  		{&testInterface, []byte{0x00, 0x00, 0x00, 0x11}, 4, nil},
   139  
   140  		// int8 - XDR Integer
   141  		{int8(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   142  		{int8(64), []byte{0x00, 0x00, 0x00, 0x40}, 4, nil},
   143  		{int8(127), []byte{0x00, 0x00, 0x00, 0x7F}, 4, nil},
   144  		{int8(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   145  		{int8(-128), []byte{0xFF, 0xFF, 0xFF, 0x80}, 4, nil},
   146  		// Expected Failure -- Short write
   147  		{int8(127), []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   148  
   149  		// uint8 - XDR Unsigned Integer
   150  		{uint8(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   151  		{uint8(64), []byte{0x00, 0x00, 0x00, 0x40}, 4, nil},
   152  		{uint8(255), []byte{0x00, 0x00, 0x00, 0xFF}, 4, nil},
   153  		// Expected Failure -- Short write
   154  		{uint8(255), []byte{0x00, 0x00}, 2, &MarshalError{ErrorCode: ErrIO}},
   155  
   156  		// int16 - XDR Integer
   157  		{int16(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   158  		{int16(1024), []byte{0x00, 0x00, 0x04, 0x00}, 4, nil},
   159  		{int16(32767), []byte{0x00, 0x00, 0x7F, 0xFF}, 4, nil},
   160  		{int16(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   161  		{int16(-32768), []byte{0xFF, 0xFF, 0x80, 0x00}, 4, nil},
   162  		// Expected Failure -- Short write
   163  		{int16(-32768), []byte{0xFF}, 1, &MarshalError{ErrorCode: ErrIO}},
   164  
   165  		// uint16 - XDR Unsigned Integer
   166  		{uint16(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   167  		{uint16(1024), []byte{0x00, 0x00, 0x04, 0x00}, 4, nil},
   168  		{uint16(65535), []byte{0x00, 0x00, 0xFF, 0xFF}, 4, nil},
   169  		// Expected Failure -- Short write
   170  		{uint16(65535), []byte{0x00, 0x00}, 2, &MarshalError{ErrorCode: ErrIO}},
   171  
   172  		// int32 - XDR Integer
   173  		{int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   174  		{int32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
   175  		{int32(2147483647), []byte{0x7F, 0xFF, 0xFF, 0xFF}, 4, nil},
   176  		{int32(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   177  		{int32(-2147483648), []byte{0x80, 0x00, 0x00, 0x00}, 4, nil},
   178  		// Expected Failure -- Short write
   179  		{int32(2147483647), []byte{0x7F, 0xFF, 0xFF}, 3, &MarshalError{ErrorCode: ErrIO}},
   180  
   181  		// uint32 - XDR Unsigned Integer
   182  		{uint32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   183  		{uint32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
   184  		{uint32(4294967295), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   185  		// Expected Failure -- Short write
   186  		{uint32(262144), []byte{0x00, 0x04, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   187  
   188  		// int64 - XDR Hyper Integer
   189  		{int64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   190  		{int64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   191  		{int64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   192  		{int64(9223372036854775807), []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   193  		{int64(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   194  		{int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   195  		// Expected Failure -- Short write
   196  		{int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 7, &MarshalError{ErrorCode: ErrIO}},
   197  
   198  		// uint64 - XDR Unsigned Hyper Integer
   199  		{uint64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   200  		{uint64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   201  		{uint64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   202  		{uint64(18446744073709551615), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   203  		{uint64(9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   204  		// Expected Failure -- Short write
   205  		{uint64(9223372036854775808), []byte{0x80}, 1, &MarshalError{ErrorCode: ErrIO}},
   206  
   207  		// bool - XDR Integer
   208  		{false, []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   209  		{true, []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
   210  		// Expected Failure -- Short write
   211  		{true, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   212  
   213  		// float32 - XDR Floating-Point
   214  		{float32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   215  		{float32(3.14), []byte{0x40, 0x48, 0xF5, 0xC3}, 4, nil},
   216  		{float32(1234567.0), []byte{0x49, 0x96, 0xB4, 0x38}, 4, nil},
   217  		{float32(math.Inf(-1)), []byte{0xFF, 0x80, 0x00, 0x00}, 4, nil},
   218  		{float32(math.Inf(0)), []byte{0x7F, 0x80, 0x00, 0x00}, 4, nil},
   219  		// Expected Failure -- Short write
   220  		{float32(3.14), []byte{0x40, 0x48, 0xF5}, 3, &MarshalError{ErrorCode: ErrIO}},
   221  
   222  		// float64 - XDR Double-precision Floating-Point
   223  		{float64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   224  		{float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18}, 8, nil},
   225  		{float64(math.Inf(-1)), []byte{0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   226  		{float64(math.Inf(0)), []byte{0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   227  		// Expected Failure -- Short write
   228  		{float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d}, 7, &MarshalError{ErrorCode: ErrIO}},
   229  
   230  		// string - XDR String
   231  		{"", []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   232  		{"xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, 8, nil},
   233  		{"τ=2π", []byte{0x00, 0x00, 0x00, 0x06, 0xCF, 0x84, 0x3D, 0x32, 0xCF, 0x80, 0x00, 0x00}, 12, nil},
   234  		// Expected Failures -- Short write in length and payload
   235  		{"xdr", []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   236  		{"xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78}, 5, &MarshalError{ErrorCode: ErrIO}},
   237  
   238  		// []byte - XDR Variable Opaque
   239  		{[]byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, 8, nil},
   240  		{[]byte{0x01, 0x02, 0x03}, []byte{0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00}, 8, nil},
   241  		// Expected Failures -- Short write in length and payload
   242  		{[]byte{0x01}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   243  		{[]byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01}, 5, &MarshalError{ErrorCode: ErrIO}},
   244  
   245  		// [#]byte - XDR Fixed Opaque
   246  		{[1]byte{0x01}, []byte{0x01, 0x00, 0x00, 0x00}, 4, nil}, // No & here to test unaddressable arrays
   247  		{&[2]byte{0x01, 0x02}, []byte{0x01, 0x02, 0x00, 0x00}, 4, nil},
   248  		{&[3]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03, 0x00}, 4, nil},
   249  		{&[4]byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, 4, nil},
   250  		{&[5]byte{0x01, 0x02, 0x03, 0x04, 0x05}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00}, 8, nil},
   251  		// Expected Failure -- Short write
   252  		{[1]byte{0x01}, []byte{0x01, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   253  
   254  		// []<type> - XDR Variable-Length Array
   255  		{&[]int16{512, 1024, 2048},
   256  			[]byte{0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00},
   257  			16, nil},
   258  		{[]bool{true, false}, []byte{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}, 12, nil},
   259  		// Expected Failures -- Short write in number of elements and
   260  		// payload
   261  		{[]bool{true, false}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   262  		{[]bool{true, false}, []byte{0x00, 0x00, 0x00, 0x02, 0x00}, 5, &MarshalError{ErrorCode: ErrIO}},
   263  
   264  		// [#]<type> - XDR Fixed-Length Array
   265  		{&[2]uint32{512, 1024}, []byte{0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00}, 8, nil},
   266  		// Expected Failures -- Short write in number of elements and
   267  		// payload
   268  		{[2]uint32{512, 1024}, []byte{0x00, 0x00, 0x02}, 3, &MarshalError{ErrorCode: ErrIO}},
   269  		{[2]uint32{512, 1024}, []byte{0x00, 0x00, 0x02, 0x00, 0x00}, 5, &MarshalError{ErrorCode: ErrIO}},
   270  
   271  		// map[string]uint32
   272  		{map[string]uint32{"map1": 1},
   273  			[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31, 0x00, 0x00, 0x00, 0x01},
   274  			16, nil},
   275  		// Expected Failures -- Short write in number of elements, key,
   276  		// and payload
   277  		{map[string]uint32{"map1": 1}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   278  		{map[string]uint32{"map1": 1}, []byte{0x00, 0x00, 0x00, 0x01, 0x00}, 5, &MarshalError{ErrorCode: ErrIO}},
   279  		{map[string]uint32{"map1": 1}, []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04}, 8, &MarshalError{ErrorCode: ErrIO}},
   280  		{map[string]uint32{"map1": 1},
   281  			[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31},
   282  			12, &MarshalError{ErrorCode: ErrIO}},
   283  
   284  		// time.Time - XDR String per RFC3339
   285  		{time.Unix(1396581888, 0).UTC(),
   286  			[]byte{
   287  				0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34,
   288  				0x2d, 0x30, 0x34, 0x2d, 0x30, 0x34, 0x54, 0x30,
   289  				0x33, 0x3a, 0x32, 0x34, 0x3a, 0x34, 0x38, 0x5a,
   290  			}, 24, nil},
   291  		// Expected Failure -- Short write
   292  		{time.Unix(1396581888, 0).UTC(), []byte{0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34}, 8, &MarshalError{ErrorCode: ErrIO}},
   293  
   294  		// struct - XDR Structure -- test struct contains all supported types
   295  		{&structMarshalTestIn, structMarshalTestWant, len(structMarshalTestWant), nil},
   296  		{opaqueStruct{[]uint8{1}, [1]uint8{2}},
   297  			[]byte{
   298  				0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
   299  				0x00, 0x00, 0x00, 0x02,
   300  			}, 12, nil},
   301  		// Expected Failures -- Short write in variable length,
   302  		// variable payload, and fixed payload.
   303  		{structMarshalTestIn, structMarshalTestWant[:3], 3, &MarshalError{ErrorCode: ErrIO}},
   304  		{opaqueStruct{[]uint8{1}, [1]uint8{2}}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   305  		{opaqueStruct{[]uint8{1}, [1]uint8{2}}, []byte{0x00, 0x00, 0x00, 0x01}, 4, &MarshalError{ErrorCode: ErrIO}},
   306  		{opaqueStruct{[]uint8{1}, [1]uint8{2}},
   307  			[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01},
   308  			8, &MarshalError{ErrorCode: ErrIO}},
   309  
   310  		// Expected errors
   311  		{nilInterface, []byte{}, 0, &MarshalError{ErrorCode: ErrNilInterface}},
   312  		{&nilInterface, []byte{}, 0, &MarshalError{ErrorCode: ErrNilInterface}},
   313  		{(*interface{})(nil), []byte{}, 0, &MarshalError{ErrorCode: ErrBadArguments}},
   314  		{testChan, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   315  		{&testChan, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   316  		{testFunc, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   317  		{&testFunc, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   318  		{testComplex64, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   319  		{&testComplex64, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   320  		{testComplex128, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   321  		{&testComplex128, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
   322  	}
   323  
   324  	for i, test := range tests {
   325  		data := newFixedWriter(test.wantN)
   326  		n, err := Marshal(data, test.in)
   327  
   328  		// First ensure the number of bytes written is the expected
   329  		// value and the error is the expected one.
   330  		testName := fmt.Sprintf("Marshal #%d", i)
   331  		testExpectedMRet(t, testName, n, test.wantN, err, test.err)
   332  
   333  		rv := data.Bytes()
   334  		if len(rv) != len(test.wantBytes) {
   335  			t.Errorf("%s: unexpected len - got: %v want: %v\n",
   336  				testName, len(rv), len(test.wantBytes))
   337  			continue
   338  		}
   339  		if !reflect.DeepEqual(rv, test.wantBytes) {
   340  			t.Errorf("%s: unexpected result - got: %v want: %v\n",
   341  				testName, rv, test.wantBytes)
   342  			continue
   343  		}
   344  	}
   345  }
   346  
   347  // encodeFunc is used to identify which public function of the Encoder object
   348  // a test applies to.
   349  type encodeFunc int
   350  
   351  const (
   352  	fEncodeBool encodeFunc = iota
   353  	fEncodeDouble
   354  	fEncodeEnum
   355  	fEncodeFixedOpaque
   356  	fEncodeFloat
   357  	fEncodeHyper
   358  	fEncodeInt
   359  	fEncodeOpaque
   360  	fEncodeString
   361  	fEncodeUhyper
   362  	fEncodeUint
   363  )
   364  
   365  // Map of encodeFunc values to names for pretty printing.
   366  var encodeFuncStrings = map[encodeFunc]string{
   367  	fEncodeBool:        "EncodeBool",
   368  	fEncodeDouble:      "EncodeDouble",
   369  	fEncodeEnum:        "EncodeEnum",
   370  	fEncodeFixedOpaque: "EncodeFixedOpaque",
   371  	fEncodeFloat:       "EncodeFloat",
   372  	fEncodeHyper:       "EncodeHyper",
   373  	fEncodeInt:         "EncodeInt",
   374  	fEncodeOpaque:      "EncodeOpaque",
   375  	fEncodeString:      "EncodeString",
   376  	fEncodeUhyper:      "EncodeUhyper",
   377  	fEncodeUint:        "EncodeUint",
   378  }
   379  
   380  // String implements the fmt.Stringer interface and returns the encode function
   381  // as a human-readable string.
   382  func (f encodeFunc) String() string {
   383  	if s := encodeFuncStrings[f]; s != "" {
   384  		return s
   385  	}
   386  	return fmt.Sprintf("Unknown encodeFunc (%d)", f)
   387  }
   388  
   389  // TestEncoder ensures an Encoder works as intended.
   390  func TestEncoder(t *testing.T) {
   391  	tests := []struct {
   392  		f         encodeFunc  // function to use to encode
   393  		in        interface{} // input value
   394  		wantBytes []byte      // expected bytes
   395  		wantN     int         // expected number of bytes written
   396  		err       error       // expected error
   397  	}{
   398  		// Bool
   399  		{fEncodeBool, false, []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   400  		{fEncodeBool, true, []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
   401  		// Expected Failure -- Short write
   402  		{fEncodeBool, true, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   403  
   404  		// Double
   405  		{fEncodeDouble, float64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   406  		{fEncodeDouble, float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18}, 8, nil},
   407  		{fEncodeDouble, float64(math.Inf(-1)), []byte{0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   408  		{fEncodeDouble, float64(math.Inf(0)), []byte{0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   409  		// Expected Failure -- Short write
   410  		{fEncodeDouble, float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d}, 7, &MarshalError{ErrorCode: ErrIO}},
   411  
   412  		// Enum
   413  		{fEncodeEnum, int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   414  		{fEncodeEnum, int32(1), []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
   415  		// Expected Failures -- Invalid enum values
   416  		{fEncodeEnum, int32(2), []byte{}, 0, &MarshalError{ErrorCode: ErrBadEnumValue}},
   417  		{fEncodeEnum, int32(1234), []byte{}, 0, &MarshalError{ErrorCode: ErrBadEnumValue}},
   418  
   419  		// FixedOpaque
   420  		{fEncodeFixedOpaque, []byte{0x01}, []byte{0x01, 0x00, 0x00, 0x00}, 4, nil},
   421  		{fEncodeFixedOpaque, []byte{0x01, 0x02}, []byte{0x01, 0x02, 0x00, 0x00}, 4, nil},
   422  		{fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03, 0x00}, 4, nil},
   423  		{fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, 4, nil},
   424  		{fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04, 0x05}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00}, 8, nil},
   425  		// Expected Failure -- Short write
   426  		{fEncodeFixedOpaque, []byte{0x01}, []byte{0x01, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   427  
   428  		// Float
   429  		{fEncodeFloat, float32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   430  		{fEncodeFloat, float32(3.14), []byte{0x40, 0x48, 0xF5, 0xC3}, 4, nil},
   431  		{fEncodeFloat, float32(1234567.0), []byte{0x49, 0x96, 0xB4, 0x38}, 4, nil},
   432  		{fEncodeFloat, float32(math.Inf(-1)), []byte{0xFF, 0x80, 0x00, 0x00}, 4, nil},
   433  		{fEncodeFloat, float32(math.Inf(0)), []byte{0x7F, 0x80, 0x00, 0x00}, 4, nil},
   434  		// Expected Failure -- Short write
   435  		{fEncodeFloat, float32(3.14), []byte{0x40, 0x48, 0xF5}, 3, &MarshalError{ErrorCode: ErrIO}},
   436  
   437  		// Hyper
   438  		{fEncodeHyper, int64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   439  		{fEncodeHyper, int64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   440  		{fEncodeHyper, int64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   441  		{fEncodeHyper, int64(9223372036854775807), []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   442  		{fEncodeHyper, int64(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   443  		{fEncodeHyper, int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   444  		// Expected Failure -- Short write
   445  		{fEncodeHyper, int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 7, &MarshalError{ErrorCode: ErrIO}},
   446  
   447  		// Int
   448  		{fEncodeInt, int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   449  		{fEncodeInt, int32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
   450  		{fEncodeInt, int32(2147483647), []byte{0x7F, 0xFF, 0xFF, 0xFF}, 4, nil},
   451  		{fEncodeInt, int32(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   452  		{fEncodeInt, int32(-2147483648), []byte{0x80, 0x00, 0x00, 0x00}, 4, nil},
   453  		// Expected Failure -- Short write
   454  		{fEncodeInt, int32(2147483647), []byte{0x7F, 0xFF, 0xFF}, 3, &MarshalError{ErrorCode: ErrIO}},
   455  
   456  		// Opaque
   457  		{fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, 8, nil},
   458  		{fEncodeOpaque, []byte{0x01, 0x02, 0x03}, []byte{0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00}, 8, nil},
   459  		// Expected Failures -- Short write in length and payload
   460  		{fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   461  		{fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01}, 5, &MarshalError{ErrorCode: ErrIO}},
   462  
   463  		// String
   464  		{fEncodeString, "", []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   465  		{fEncodeString, "xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, 8, nil},
   466  		{fEncodeString, "τ=2π", []byte{0x00, 0x00, 0x00, 0x06, 0xCF, 0x84, 0x3D, 0x32, 0xCF, 0x80, 0x00, 0x00}, 12, nil},
   467  		// Expected Failures -- Short write in length and payload
   468  		{fEncodeString, "xdr", []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   469  		{fEncodeString, "xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78}, 5, &MarshalError{ErrorCode: ErrIO}},
   470  
   471  		// Uhyper
   472  		{fEncodeUhyper, uint64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   473  		{fEncodeUhyper, uint64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   474  		{fEncodeUhyper, uint64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   475  		{fEncodeUhyper, uint64(18446744073709551615), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   476  		{fEncodeUhyper, uint64(9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   477  		// Expected Failure -- Short write
   478  		{fEncodeUhyper, uint64(9223372036854775808), []byte{0x80}, 1, &MarshalError{ErrorCode: ErrIO}},
   479  
   480  		// Uint
   481  		{fEncodeUint, uint32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   482  		{fEncodeUint, uint32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
   483  		{fEncodeUint, uint32(4294967295), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   484  		// Expected Failure -- Short write
   485  		{fEncodeUint, uint32(262144), []byte{0x00, 0x04, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   486  	}
   487  
   488  	validEnums := make(map[int32]bool)
   489  	validEnums[0] = true
   490  	validEnums[1] = true
   491  
   492  	var err error
   493  	var n int
   494  
   495  	for i, test := range tests {
   496  		err = nil
   497  		data := newFixedWriter(test.wantN)
   498  		enc := NewEncoder(data)
   499  		switch test.f {
   500  		case fEncodeBool:
   501  			in := test.in.(bool)
   502  			n, err = enc.EncodeBool(in)
   503  		case fEncodeDouble:
   504  			in := test.in.(float64)
   505  			n, err = enc.EncodeDouble(in)
   506  		case fEncodeEnum:
   507  			in := test.in.(int32)
   508  			n, err = enc.EncodeEnum(in, validEnums)
   509  		case fEncodeFixedOpaque:
   510  			in := test.in.([]byte)
   511  			n, err = enc.EncodeFixedOpaque(in)
   512  		case fEncodeFloat:
   513  			in := test.in.(float32)
   514  			n, err = enc.EncodeFloat(in)
   515  		case fEncodeHyper:
   516  			in := test.in.(int64)
   517  			n, err = enc.EncodeHyper(in)
   518  		case fEncodeInt:
   519  			in := test.in.(int32)
   520  			n, err = enc.EncodeInt(in)
   521  		case fEncodeOpaque:
   522  			in := test.in.([]byte)
   523  			n, err = enc.EncodeOpaque(in)
   524  		case fEncodeString:
   525  			in := test.in.(string)
   526  			n, err = enc.EncodeString(in)
   527  		case fEncodeUhyper:
   528  			in := test.in.(uint64)
   529  			n, err = enc.EncodeUhyper(in)
   530  		case fEncodeUint:
   531  			in := test.in.(uint32)
   532  			n, err = enc.EncodeUint(in)
   533  		default:
   534  			t.Errorf("%v #%d unrecognized function", test.f, i)
   535  			continue
   536  		}
   537  
   538  		// First ensure the number of bytes written is the expected
   539  		// value and the error is the expected one.
   540  		testName := fmt.Sprintf("%v #%d", test.f, i)
   541  		testExpectedMRet(t, testName, n, test.wantN, err, test.err)
   542  
   543  		// Finally, ensure the written bytes are what is expected.
   544  		rv := data.Bytes()
   545  		if len(rv) != len(test.wantBytes) {
   546  			t.Errorf("%s: unexpected len - got: %v want: %v\n",
   547  				testName, len(rv), len(test.wantBytes))
   548  			continue
   549  		}
   550  		if !reflect.DeepEqual(rv, test.wantBytes) {
   551  			t.Errorf("%s: unexpected result - got: %v want: %v\n",
   552  				testName, rv, test.wantBytes)
   553  			continue
   554  		}
   555  	}
   556  }
   557  
   558  // TestMarshalCorners ensures the Marshal function properly handles various
   559  // cases not already covered by the other tests.
   560  func TestMarshalCorners(t *testing.T) {
   561  	// Ensure encode of an invalid reflect value returns the expected
   562  	// error.
   563  	testName := "Encode invalid reflect value"
   564  	expectedN := 0
   565  	expectedErr := error(&MarshalError{ErrorCode: ErrUnsupportedType})
   566  	expectedVal := []byte{}
   567  	data := newFixedWriter(expectedN)
   568  	n, err := TstEncode(data)(reflect.Value{})
   569  	testExpectedMRet(t, testName, n, expectedN, err, expectedErr)
   570  	if !reflect.DeepEqual(data.Bytes(), expectedVal) {
   571  		t.Errorf("%s: unexpected result - got: %x want: %x\n",
   572  			testName, data.Bytes(), expectedVal)
   573  	}
   574  
   575  	// Ensure marshal of a struct with both exported and unexported fields
   576  	// skips the unexported fields but still marshals to the exported
   577  	// fields.
   578  	type unexportedStruct struct {
   579  		unexported int
   580  		Exported   int
   581  	}
   582  	testName = "Marshal struct with exported and unexported fields"
   583  	tstruct := unexportedStruct{0, 1}
   584  	expectedN = 4
   585  	expectedErr = nil
   586  	expectedVal = []byte{0x00, 0x00, 0x00, 0x01}
   587  	data = newFixedWriter(expectedN)
   588  	n, err = Marshal(data, tstruct)
   589  	testExpectedMRet(t, testName, n, expectedN, err, expectedErr)
   590  	if !reflect.DeepEqual(data.Bytes(), expectedVal) {
   591  		t.Errorf("%s: unexpected result - got: %x want: %x\n",
   592  			testName, data.Bytes(), expectedVal)
   593  	}
   594  
   595  }