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