github.com/stellar/go-xdr@v0.0.0-20231122183749-b53fb00bcac2/xdr3/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/xdr3"
    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  	// enum encoding
   347  
   348  	// good enum
   349  	w := newFixedWriter(4)
   350  	n, err := Marshal(w, AnEnum(1))
   351  	rv := w.Bytes()
   352  
   353  	if err != nil {
   354  		t.Errorf("enum encode: unexpected err - got: %v\n", err)
   355  	}
   356  
   357  	if n != 4 {
   358  		t.Errorf("enum encode: unexpected len - got: %v want: 4\n", n)
   359  	}
   360  
   361  	if !reflect.DeepEqual([]byte{0x00, 0x00, 0x00, 0x01}, rv) {
   362  		t.Errorf("enum encode: unexpected result - got: %v", rv)
   363  	}
   364  
   365  	// bad enum
   366  	w = newFixedWriter(4)
   367  	_, err = Marshal(w, AnEnum(3))
   368  	rv = w.Bytes()
   369  
   370  	if err == nil {
   371  		t.Errorf("enum encode: expected err, got nil")
   372  	}
   373  
   374  	// Optional fields
   375  	var opt *int32
   376  
   377  	// nil
   378  	w = newFixedWriter(4)
   379  	n, err = TstEncode(w)(reflect.ValueOf(opt))
   380  	rv = w.Bytes()
   381  
   382  	if err != nil {
   383  		t.Errorf("optional encode: unexpected err - got: %v\n", err)
   384  	}
   385  
   386  	if n != 4 {
   387  		t.Errorf("optional encode: unexpected len - got: %v want: 4\n", n)
   388  	}
   389  
   390  	if !reflect.DeepEqual([]byte{0x00, 0x00, 0x00, 0x00}, rv) {
   391  		t.Errorf("optional encode: unexpected result - got: %v", rv)
   392  	}
   393  
   394  	//non-nil
   395  	opt = new(int32)
   396  	*opt = 4
   397  	w = newFixedWriter(8)
   398  	n, err = TstEncode(w)(reflect.ValueOf(opt))
   399  	rv = w.Bytes()
   400  
   401  	if err != nil {
   402  		t.Errorf("optional encode: unexpected err - got: %v\n", err)
   403  	}
   404  
   405  	if n != 8 {
   406  		t.Errorf("optional encode: unexpected len - got: %v want: 8\n", n)
   407  	}
   408  
   409  	if !reflect.DeepEqual([]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04}, rv) {
   410  		t.Errorf("optional encode: unexpected result - got: %v", rv)
   411  	}
   412  
   413  	// Union encoding
   414  	// void arm
   415  	var u aUnion
   416  	u.Type = AnEnum(2)
   417  	w = newFixedWriter(4)
   418  	n, err = Marshal(w, u)
   419  	rv = w.Bytes()
   420  
   421  	if err != nil {
   422  		t.Errorf("union encode: unexpected err - got: %v\n", err)
   423  	}
   424  
   425  	if n != 4 {
   426  		t.Errorf("union encode: unexpected len - got: %v want: 4\n", n)
   427  	}
   428  
   429  	if !reflect.DeepEqual([]byte{0x00, 0x00, 0x00, 0x02}, rv) {
   430  		t.Errorf("union encode: unexpected result - got: %v", rv)
   431  	}
   432  
   433  	// non-void arm
   434  	u.Type = AnEnum(0)
   435  	u.Data = new(int32)
   436  	*u.Data = 4
   437  	w = newFixedWriter(8)
   438  	n, err = Marshal(w, u)
   439  	rv = w.Bytes()
   440  
   441  	if err != nil {
   442  		t.Errorf("union encode: unexpected err - got: %v\n", err)
   443  	}
   444  
   445  	if n != 8 {
   446  		t.Errorf("union encode: unexpected len - got: %v want: 8\n", n)
   447  	}
   448  
   449  	if !reflect.DeepEqual([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, rv) {
   450  		t.Errorf("union encode: unexpected result - got: %v", rv)
   451  	}
   452  
   453  	// invalid switch
   454  	u.Type = AnEnum(2)
   455  	w = newFixedWriter(0)
   456  	n, err = Marshal(w, u)
   457  
   458  	if err == nil {
   459  		t.Errorf("union encode: expected err, got nil\n")
   460  	}
   461  
   462  	if n != 0 {
   463  		t.Errorf("union encode: unexpected len - got: %v want: 0\n", n)
   464  	}
   465  
   466  	// invalid arm
   467  	u.Type = AnEnum(-1)
   468  	u.Data = nil
   469  	w = newFixedWriter(0)
   470  	n, err = Marshal(w, u)
   471  
   472  	if err == nil {
   473  		t.Errorf("union encode: expected err, got nil\n")
   474  	}
   475  
   476  	if n != 0 {
   477  		t.Errorf("union encode: unexpected len - got: %v want: 0\n", n)
   478  	}
   479  
   480  	// invalid value
   481  	u.Type = AnEnum(0)
   482  	u.Data = nil
   483  	w = newFixedWriter(0)
   484  	n, err = Marshal(w, u)
   485  
   486  	if err == nil {
   487  		t.Errorf("union encode: expected err, got nil\n")
   488  	}
   489  
   490  	if n != 0 {
   491  		t.Errorf("union encode: unexpected len - got: %v want: 0\n", n)
   492  	}
   493  }
   494  
   495  // encodeFunc is used to identify which public function of the Encoder object
   496  // a test applies to.
   497  type encodeFunc int
   498  
   499  const (
   500  	fEncodeBool encodeFunc = iota
   501  	fEncodeDouble
   502  	fEncodeEnum
   503  	fEncodeFixedOpaque
   504  	fEncodeFloat
   505  	fEncodeHyper
   506  	fEncodeInt
   507  	fEncodeOpaque
   508  	fEncodeString
   509  	fEncodeUhyper
   510  	fEncodeUint
   511  )
   512  
   513  // Map of encodeFunc values to names for pretty printing.
   514  var encodeFuncStrings = map[encodeFunc]string{
   515  	fEncodeBool:        "EncodeBool",
   516  	fEncodeDouble:      "EncodeDouble",
   517  	fEncodeEnum:        "EncodeEnum",
   518  	fEncodeFixedOpaque: "EncodeFixedOpaque",
   519  	fEncodeFloat:       "EncodeFloat",
   520  	fEncodeHyper:       "EncodeHyper",
   521  	fEncodeInt:         "EncodeInt",
   522  	fEncodeOpaque:      "EncodeOpaque",
   523  	fEncodeString:      "EncodeString",
   524  	fEncodeUhyper:      "EncodeUhyper",
   525  	fEncodeUint:        "EncodeUint",
   526  }
   527  
   528  // String implements the fmt.Stringer interface and returns the encode function
   529  // as a human-readable string.
   530  func (f encodeFunc) String() string {
   531  	if s := encodeFuncStrings[f]; s != "" {
   532  		return s
   533  	}
   534  	return fmt.Sprintf("Unknown encodeFunc (%d)", f)
   535  }
   536  
   537  // TestEncoder ensures an Encoder works as intended.
   538  func TestEncoder(t *testing.T) {
   539  	tests := []struct {
   540  		f         encodeFunc  // function to use to encode
   541  		in        interface{} // input value
   542  		wantBytes []byte      // expected bytes
   543  		wantN     int         // expected number of bytes written
   544  		err       error       // expected error
   545  	}{
   546  		// Bool
   547  		{fEncodeBool, false, []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   548  		{fEncodeBool, true, []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
   549  		// Expected Failure -- Short write
   550  		{fEncodeBool, true, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   551  
   552  		// Double
   553  		{fEncodeDouble, float64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   554  		{fEncodeDouble, float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18}, 8, nil},
   555  		{fEncodeDouble, float64(math.Inf(-1)), []byte{0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   556  		{fEncodeDouble, float64(math.Inf(0)), []byte{0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   557  		// Expected Failure -- Short write
   558  		{fEncodeDouble, float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d}, 7, &MarshalError{ErrorCode: ErrIO}},
   559  
   560  		// Enum
   561  		{fEncodeEnum, int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   562  		{fEncodeEnum, int32(1), []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
   563  		// Expected Failures -- Invalid enum values
   564  		{fEncodeEnum, int32(2), []byte{}, 0, &MarshalError{ErrorCode: ErrBadEnumValue}},
   565  		{fEncodeEnum, int32(1234), []byte{}, 0, &MarshalError{ErrorCode: ErrBadEnumValue}},
   566  
   567  		// FixedOpaque
   568  		{fEncodeFixedOpaque, []byte{0x01}, []byte{0x01, 0x00, 0x00, 0x00}, 4, nil},
   569  		{fEncodeFixedOpaque, []byte{0x01, 0x02}, []byte{0x01, 0x02, 0x00, 0x00}, 4, nil},
   570  		{fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03, 0x00}, 4, nil},
   571  		{fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, 4, nil},
   572  		{fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04, 0x05}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00}, 8, nil},
   573  		// Expected Failure -- Short write
   574  		{fEncodeFixedOpaque, []byte{0x01}, []byte{0x01, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   575  
   576  		// Float
   577  		{fEncodeFloat, float32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   578  		{fEncodeFloat, float32(3.14), []byte{0x40, 0x48, 0xF5, 0xC3}, 4, nil},
   579  		{fEncodeFloat, float32(1234567.0), []byte{0x49, 0x96, 0xB4, 0x38}, 4, nil},
   580  		{fEncodeFloat, float32(math.Inf(-1)), []byte{0xFF, 0x80, 0x00, 0x00}, 4, nil},
   581  		{fEncodeFloat, float32(math.Inf(0)), []byte{0x7F, 0x80, 0x00, 0x00}, 4, nil},
   582  		// Expected Failure -- Short write
   583  		{fEncodeFloat, float32(3.14), []byte{0x40, 0x48, 0xF5}, 3, &MarshalError{ErrorCode: ErrIO}},
   584  
   585  		// Hyper
   586  		{fEncodeHyper, int64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   587  		{fEncodeHyper, int64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   588  		{fEncodeHyper, int64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   589  		{fEncodeHyper, int64(9223372036854775807), []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   590  		{fEncodeHyper, int64(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   591  		{fEncodeHyper, int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   592  		// Expected Failure -- Short write
   593  		{fEncodeHyper, int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 7, &MarshalError{ErrorCode: ErrIO}},
   594  
   595  		// Int
   596  		{fEncodeInt, int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   597  		{fEncodeInt, int32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
   598  		{fEncodeInt, int32(2147483647), []byte{0x7F, 0xFF, 0xFF, 0xFF}, 4, nil},
   599  		{fEncodeInt, int32(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   600  		{fEncodeInt, int32(-2147483648), []byte{0x80, 0x00, 0x00, 0x00}, 4, nil},
   601  		// Expected Failure -- Short write
   602  		{fEncodeInt, int32(2147483647), []byte{0x7F, 0xFF, 0xFF}, 3, &MarshalError{ErrorCode: ErrIO}},
   603  
   604  		// Opaque
   605  		{fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, 8, nil},
   606  		{fEncodeOpaque, []byte{0x01, 0x02, 0x03}, []byte{0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00}, 8, nil},
   607  		// Expected Failures -- Short write in length and payload
   608  		{fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   609  		{fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01}, 5, &MarshalError{ErrorCode: ErrIO}},
   610  
   611  		// String
   612  		{fEncodeString, "", []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   613  		{fEncodeString, "xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, 8, nil},
   614  		{fEncodeString, "τ=2π", []byte{0x00, 0x00, 0x00, 0x06, 0xCF, 0x84, 0x3D, 0x32, 0xCF, 0x80, 0x00, 0x00}, 12, nil},
   615  		// Expected Failures -- Short write in length and payload
   616  		{fEncodeString, "xdr", []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   617  		{fEncodeString, "xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78}, 5, &MarshalError{ErrorCode: ErrIO}},
   618  
   619  		// Uhyper
   620  		{fEncodeUhyper, uint64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   621  		{fEncodeUhyper, uint64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   622  		{fEncodeUhyper, uint64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   623  		{fEncodeUhyper, uint64(18446744073709551615), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
   624  		{fEncodeUhyper, uint64(9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
   625  		// Expected Failure -- Short write
   626  		{fEncodeUhyper, uint64(9223372036854775808), []byte{0x80}, 1, &MarshalError{ErrorCode: ErrIO}},
   627  
   628  		// Uint
   629  		{fEncodeUint, uint32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
   630  		{fEncodeUint, uint32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
   631  		{fEncodeUint, uint32(4294967295), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
   632  		// Expected Failure -- Short write
   633  		{fEncodeUint, uint32(262144), []byte{0x00, 0x04, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
   634  	}
   635  
   636  	validEnums := make(map[int32]bool)
   637  	validEnums[0] = true
   638  	validEnums[1] = true
   639  
   640  	var err error
   641  	var n int
   642  
   643  	for i, test := range tests {
   644  		err = nil
   645  		data := newFixedWriter(test.wantN)
   646  		enc := NewEncoder(data)
   647  		switch test.f {
   648  		case fEncodeBool:
   649  			in := test.in.(bool)
   650  			n, err = enc.EncodeBool(in)
   651  		case fEncodeDouble:
   652  			in := test.in.(float64)
   653  			n, err = enc.EncodeDouble(in)
   654  		case fEncodeEnum:
   655  			in := test.in.(int32)
   656  			n, err = enc.EncodeEnum(in, validEnums)
   657  		case fEncodeFixedOpaque:
   658  			in := test.in.([]byte)
   659  			n, err = enc.EncodeFixedOpaque(in)
   660  		case fEncodeFloat:
   661  			in := test.in.(float32)
   662  			n, err = enc.EncodeFloat(in)
   663  		case fEncodeHyper:
   664  			in := test.in.(int64)
   665  			n, err = enc.EncodeHyper(in)
   666  		case fEncodeInt:
   667  			in := test.in.(int32)
   668  			n, err = enc.EncodeInt(in)
   669  		case fEncodeOpaque:
   670  			in := test.in.([]byte)
   671  			n, err = enc.EncodeOpaque(in)
   672  		case fEncodeString:
   673  			in := test.in.(string)
   674  			n, err = enc.EncodeString(in)
   675  		case fEncodeUhyper:
   676  			in := test.in.(uint64)
   677  			n, err = enc.EncodeUhyper(in)
   678  		case fEncodeUint:
   679  			in := test.in.(uint32)
   680  			n, err = enc.EncodeUint(in)
   681  		default:
   682  			t.Errorf("%v #%d unrecognized function", test.f, i)
   683  			continue
   684  		}
   685  
   686  		// First ensure the number of bytes written is the expected
   687  		// value and the error is the expected one.
   688  		testName := fmt.Sprintf("%v #%d", test.f, i)
   689  		testExpectedMRet(t, testName, n, test.wantN, err, test.err)
   690  
   691  		// Finally, ensure the written bytes are what is expected.
   692  		rv := data.Bytes()
   693  		if len(rv) != len(test.wantBytes) {
   694  			t.Errorf("%s: unexpected len - got: %v want: %v\n",
   695  				testName, len(rv), len(test.wantBytes))
   696  			continue
   697  		}
   698  		if !reflect.DeepEqual(rv, test.wantBytes) {
   699  			t.Errorf("%s: unexpected result - got: %v want: %v\n",
   700  				testName, rv, test.wantBytes)
   701  			continue
   702  		}
   703  	}
   704  }
   705  
   706  // TestMarshalCorners ensures the Marshal function properly handles various
   707  // cases not already covered by the other tests.
   708  func TestMarshalCorners(t *testing.T) {
   709  	// Ensure encode of an invalid reflect value returns the expected
   710  	// error.
   711  	testName := "Encode invalid reflect value"
   712  	expectedN := 0
   713  	expectedErr := error(&MarshalError{ErrorCode: ErrUnsupportedType})
   714  	expectedVal := []byte{}
   715  	data := newFixedWriter(expectedN)
   716  	n, err := TstEncode(data)(reflect.Value{})
   717  	testExpectedMRet(t, testName, n, expectedN, err, expectedErr)
   718  	if !reflect.DeepEqual(data.Bytes(), expectedVal) {
   719  		t.Errorf("%s: unexpected result - got: %x want: %x\n",
   720  			testName, data.Bytes(), expectedVal)
   721  	}
   722  
   723  	// Ensure marshal of a struct with both exported and unexported fields
   724  	// skips the unexported fields but still marshals to the exported
   725  	// fields.
   726  	type unexportedStruct struct {
   727  		unexported int
   728  		Exported   int
   729  	}
   730  	testName = "Marshal struct with exported and unexported fields"
   731  	tstruct := unexportedStruct{0, 1}
   732  	expectedN = 4
   733  	expectedErr = nil
   734  	expectedVal = []byte{0x00, 0x00, 0x00, 0x01}
   735  	data = newFixedWriter(expectedN)
   736  	n, err = Marshal(data, tstruct)
   737  	testExpectedMRet(t, testName, n, expectedN, err, expectedErr)
   738  	if !reflect.DeepEqual(data.Bytes(), expectedVal) {
   739  		t.Errorf("%s: unexpected result - got: %x want: %x\n",
   740  			testName, data.Bytes(), expectedVal)
   741  	}
   742  
   743  }