github.com/abemedia/appcast@v0.4.0/integrations/apt/deb/encode_test.go (about) 1 package deb_test 2 3 import ( 4 "errors" 5 "testing" 6 "time" 7 8 "github.com/abemedia/appcast/integrations/apt/deb" 9 "github.com/abemedia/appcast/internal/test" 10 "github.com/google/go-cmp/cmp" 11 "github.com/google/go-cmp/cmp/cmpopts" 12 ) 13 14 func TestMarshal(t *testing.T) { 15 in := record{ 16 String: "test", 17 Hex: [4]byte{1, 2, 3, 4}, 18 Int: 1, 19 Int8: 1, 20 Int16: 1, 21 Int32: 1, 22 Uint: 1, 23 Uint8: 1, 24 Uint16: 1, 25 Uint32: 1, 26 Float32: 1.123, 27 Float64: 1.123, 28 Stringer: stringer{"test"}, 29 Marshaler: &marshaler{"test"}, 30 Date: time.Date(2023, 1, 10, 19, 4, 25, 0, time.UTC), 31 } 32 33 want := `String: test 34 Hex: 01020304 35 Int: 1 36 Int8: 1 37 Int16: 1 38 Int32: 1 39 Uint: 1 40 Uint8: 1 41 Uint16: 1 42 Uint32: 1 43 Float32: 1.123 44 Float64: 1.123 45 Stringer: test 46 Marshaler: test 47 Date: Tue, 10 Jan 2023 19:04:25 UTC 48 ` 49 50 tests := []struct { 51 msg string 52 in any 53 want string 54 }{ 55 { 56 msg: "struct", 57 in: in, 58 want: want, 59 }, 60 { 61 msg: "struct pointer", 62 in: &in, 63 want: want, 64 }, 65 { 66 msg: "struct slice", 67 in: []record{in, in}, 68 want: want + "\n" + want, 69 }, 70 { 71 msg: "struct pointer slice", 72 in: []*record{&in, &in}, 73 want: want + "\n" + want, 74 }, 75 { 76 msg: "multi-line text", 77 in: record{ 78 String: "foo\nbar\nbaz\n\nfoobar", 79 Stringer: stringer{"foo\nbar\nbaz\n\nfoobar"}, 80 Marshaler: &marshaler{"foo\nbar\nbaz\n\nfoobar"}, 81 }, 82 want: `String: foo 83 bar 84 baz 85 . 86 foobar 87 Stringer: foo 88 bar 89 baz 90 . 91 foobar 92 Marshaler: foo 93 bar 94 baz 95 . 96 foobar 97 `, 98 }, 99 { 100 msg: "multi-line text starting with empty line", 101 in: record{ 102 String: "\nfoo\nbar", 103 Stringer: stringer{"\nfoo\nbar"}, 104 Marshaler: &marshaler{"\nfoo\nbar"}, 105 }, 106 want: `String: 107 foo 108 bar 109 Stringer: 110 foo 111 bar 112 Marshaler: 113 foo 114 bar 115 `, 116 }, 117 { 118 msg: "nil values", 119 in: struct { 120 Date *time.Time 121 Marshaler *marshaler 122 Stringer *stringer 123 String *string 124 Int *int 125 Uint *uint 126 Float *float64 127 }{}, 128 want: "", 129 }, 130 { 131 msg: "zero values", 132 in: struct { 133 Marshaler *marshaler 134 Stringer *stringer 135 String *string 136 }{ 137 Marshaler: &marshaler{}, 138 Stringer: &stringer{}, 139 String: new(string), 140 }, 141 want: "", 142 }, 143 { 144 msg: "unexported/ignored fields", 145 in: struct { 146 unexported string 147 Ignored string `deb:"-"` 148 Test string 149 }{unexported: "foo", Ignored: "bar", Test: "baz"}, 150 want: "Test: baz\n", 151 }, 152 { 153 msg: "named fields", 154 in: struct { 155 Name string `deb:"Alias"` //nolint:tagliatelle 156 }{Name: "foo"}, 157 want: "Alias: foo\n", 158 }, 159 } 160 161 for _, test := range tests { 162 b, err := deb.Marshal(test.in) 163 if err != nil { 164 t.Error(test.msg, err) 165 } 166 167 if diff := cmp.Diff(test.want, string(b)); diff != "" { 168 t.Errorf("%s:\n%s", test.msg, diff) 169 } 170 } 171 } 172 173 func TestEncodeErrors(t *testing.T) { 174 tests := []struct { 175 msg string 176 value any 177 err string 178 }{ 179 { 180 msg: "nil", 181 value: nil, 182 err: "unsupported type: nil", 183 }, 184 { 185 msg: "unsupported type", 186 value: &[]struct{ V complex128 }{}, 187 err: "unsupported type: complex128", 188 }, 189 { 190 msg: "marshaler error", 191 value: &[]struct{ V *errMarshaler }{{V: &errMarshaler{errors.New("marshal error")}}}, 192 err: "marshal error", 193 }, 194 } 195 196 opts := test.CompareErrorMessages() 197 198 for _, test := range tests { 199 _, err := deb.Marshal(test.value) 200 if diff := cmp.Diff(errors.New(test.err), err, opts); diff != "" { 201 t.Errorf("%s returned unexpected error:\n%s", test.msg, diff) 202 } 203 } 204 205 // Ensure write errors are passed though from each part of the application. 206 // Test up to 6 writes: field name, colon, space, value, newline (field end), newline (slice element end) 207 for i := 1; i <= 6; i++ { 208 want := errors.New("custom error") 209 w := &errWriter{i, want} 210 err := deb.NewEncoder(w).Encode([]record{{String: "foo"}, {String: "bar"}}) 211 if diff := cmp.Diff(err, want, cmpopts.EquateErrors()); diff != "" { 212 t.Errorf("write %d should return error:\n%s", i, diff) 213 } 214 } 215 } 216 217 func BenchmarkMarshal(b *testing.B) { 218 type record struct { 219 String string 220 Hex [4]byte 221 Int int 222 } 223 224 v := []record{ 225 { 226 String: "foo\nbar\nbaz", 227 Hex: [4]byte{1, 2, 3, 4}, 228 Int: 1, 229 }, 230 { 231 String: "foo\nbar\nbaz", 232 Hex: [4]byte{1, 2, 3, 4}, 233 Int: 1, 234 }, 235 } 236 237 for i := 0; i < b.N; i++ { 238 deb.Marshal(v) 239 } 240 } 241 242 type errWriter struct { 243 n int 244 e error 245 } 246 247 func (w *errWriter) Write(p []byte) (int, error) { 248 w.n-- 249 if w.n == 0 { 250 return 0, w.e 251 } 252 return len(p), nil 253 }