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  }