github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/integrations/apt/deb/decode_test.go (about) 1 package deb_test 2 3 import ( 4 "errors" 5 "io" 6 "reflect" 7 "strings" 8 "testing" 9 "testing/iotest" 10 "time" 11 12 "github.com/google/go-cmp/cmp" 13 14 "github.com/kubri/kubri/integrations/apt/deb" 15 "github.com/kubri/kubri/internal/test" 16 ) 17 18 func TestUnmarshal(t *testing.T) { 19 in := `String: test 20 Hex: 01020304 21 Int: 1 22 Int8: 1 23 Int16: 1 24 Int32: 1 25 Uint: 1 26 Uint8: 1 27 Uint16: 1 28 Uint32: 1 29 Float32: 1.123 30 Float64: 1.123 31 Marshaler: test 32 Date: Tue, 10 Jan 2023 19:04:25 UTC 33 ` 34 35 want := record{ 36 String: "test", 37 Hex: [4]byte{1, 2, 3, 4}, 38 Int: 1, 39 Int8: 1, 40 Int16: 1, 41 Int32: 1, 42 Uint: 1, 43 Uint8: 1, 44 Uint16: 1, 45 Uint32: 1, 46 Float32: 1.123, 47 Float64: 1.123, 48 Marshaler: &marshaler{"test"}, 49 Date: time.Date(2023, 1, 10, 19, 4, 25, 0, time.UTC), 50 } 51 52 tests := []struct { 53 msg string 54 in string 55 want any 56 }{ 57 { 58 msg: "struct", 59 in: in, 60 want: want, 61 }, 62 { 63 msg: "struct pointer", 64 in: in, 65 want: &want, 66 }, 67 { 68 msg: "struct slice", 69 in: in + "\r\n\r\n" + in, 70 want: []record{want, want}, 71 }, 72 { 73 msg: "struct pointer slice", 74 in: in + "\n" + in, 75 want: []*record{&want, &want}, 76 }, 77 { 78 msg: "multi-line text", 79 in: `String: foo 80 bar 81 baz 82 . 83 foobar 84 Marshaler: foo 85 bar 86 baz 87 . 88 foobar 89 `, 90 want: record{ 91 String: "foo\nbar\nbaz\n\nfoobar", 92 Marshaler: &marshaler{"foo\nbar\nbaz\n\nfoobar"}, 93 }, 94 }, 95 { 96 msg: "multi-line text starting with empty line", 97 in: `String: 98 foo 99 bar 100 Marshaler: 101 foo 102 bar 103 `, 104 want: record{ 105 String: "\nfoo\nbar", 106 Marshaler: &marshaler{"\nfoo\nbar"}, 107 }, 108 }, 109 { 110 msg: "empty values", 111 in: `String: 112 Hex: 113 Int: 114 Int8: 115 Int16: 116 Int32: 117 Uint: 118 Uint8: 119 Uint16: 120 Uint32: 121 Float32: 122 Float64: 123 Marshaler: 124 Date: 125 `, 126 want: record{}, 127 }, 128 { 129 msg: "unknown keys", 130 in: `Foo: bar 131 String: test 132 `, 133 want: record{ 134 String: "test", 135 }, 136 }, 137 { 138 msg: "non-pointer unmarshaler", 139 in: `Marshaler: test 140 `, 141 want: struct{ Marshaler marshaler }{ 142 Marshaler: marshaler{"test"}, 143 }, 144 }, 145 { 146 msg: "unexported/ignored fields", 147 in: "unexported: foo\nIgnored: bar\nTest: baz\n", 148 want: struct { 149 unexported string 150 Ignored string `deb:"-"` 151 Test string 152 }{Test: "baz"}, 153 }, 154 { 155 msg: "named fields", 156 in: "Alias: foo\n", 157 want: struct { 158 Name string `deb:"Alias"` //nolint:tagliatelle 159 }{Name: "foo"}, 160 }, 161 } 162 163 opts := test.ExportAll() 164 165 for _, test := range tests { 166 v := reflect.New(reflect.TypeOf(test.want)) 167 if err := deb.Unmarshal([]byte(test.in), v.Interface()); err != nil { 168 t.Error(test.msg, err) 169 } else { 170 if diff := cmp.Diff(test.want, v.Elem().Interface(), opts); diff != "" { 171 t.Errorf("%s:\n%s", test.msg, diff) 172 } 173 } 174 } 175 } 176 177 func TestDecodeErrors(t *testing.T) { 178 tests := []struct { 179 msg string 180 reader io.Reader 181 value any 182 err string 183 }{ 184 { 185 msg: "non-pointer", 186 value: record{}, 187 err: "must use pointer", 188 }, 189 { 190 msg: "struct reader error", 191 reader: iotest.ErrReader(errors.New("reader error")), 192 value: &record{}, 193 err: "reader error", 194 }, 195 { 196 msg: "slice reader error", 197 reader: iotest.ErrReader(errors.New("reader error")), 198 value: &[]record{{}}, 199 err: "reader error", 200 }, 201 { 202 msg: "nil", 203 value: nil, 204 err: "unsupported type: nil", 205 }, 206 { 207 msg: "unsupported type", 208 value: &[]struct{ V complex128 }{}, 209 err: "unsupported type: complex128", 210 }, 211 { 212 msg: "invalid date", 213 reader: strings.NewReader("Date: test\n"), 214 value: &[]record{}, 215 err: `parsing time "test" as "Mon, 02 Jan 2006 15:04:05 MST": cannot parse "test" as "Mon"`, 216 }, 217 { 218 msg: "invalid integer", 219 reader: strings.NewReader("Int: test\n"), 220 value: &[]record{}, 221 err: `strconv.ParseInt: parsing "test": invalid syntax`, 222 }, 223 { 224 msg: "invalid unsigned integer", 225 reader: strings.NewReader("Uint: test\n"), 226 value: &[]record{}, 227 err: `strconv.ParseUint: parsing "test": invalid syntax`, 228 }, 229 { 230 msg: "invalid float", 231 reader: strings.NewReader("Float64: test\n"), 232 value: &[]record{}, 233 err: `strconv.ParseFloat: parsing "test": invalid syntax`, 234 }, 235 { 236 msg: "invalid hex data", 237 reader: strings.NewReader("Hex: test\n"), 238 value: &[]record{}, 239 err: "encoding/hex: invalid byte: U+0074 't'", 240 }, 241 { 242 msg: "invalid hex length", 243 reader: strings.NewReader("Hex: FFFFFFFFFF\n"), 244 value: &[]record{}, 245 err: "hex data would overflow byte array", 246 }, 247 { 248 msg: "invalid line", 249 reader: strings.NewReader("Foo\nBar:"), 250 value: &[]record{}, 251 err: `invalid line: "Foo"`, 252 }, 253 { 254 msg: "missing colon", 255 reader: strings.NewReader("String"), 256 value: &[]record{}, 257 err: "unexpected end of input", 258 }, 259 { 260 msg: "missing line feed", 261 reader: strings.NewReader("String:"), 262 value: &[]record{}, 263 err: "unexpected end of input", 264 }, 265 { 266 msg: "unmarshaler error", 267 reader: strings.NewReader("Marshaler: test\n"), 268 value: &struct{ Marshaler errMarshaler }{ 269 Marshaler: errMarshaler{errors.New("unmarshal error")}, 270 }, 271 err: "unmarshal error", 272 }, 273 } 274 275 opts := test.CompareErrorMessages() 276 277 for _, test := range tests { 278 err := deb.NewDecoder(test.reader).Decode(test.value) 279 if diff := cmp.Diff(errors.New(test.err), err, opts); diff != "" { 280 t.Errorf("%s returned unexpected error:\n%s", test.msg, diff) 281 } 282 } 283 } 284 285 func BenchmarkUnmarshal(b *testing.B) { 286 type record struct { 287 String string 288 Hex [4]byte 289 Int int 290 } 291 292 in := []byte(`String: foo 293 bar 294 baz 295 Hex: 01020304 296 Int: 1 297 298 String: foo 299 bar 300 baz 301 Hex: 01020304 302 Int: 1 303 `) 304 305 var v []record 306 307 for i := 0; i < b.N; i++ { 308 deb.Unmarshal(in, &v) 309 } 310 }