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  }