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 }