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 }