From b7b9dfb569ab85566a6d9bc876597f73927460c3 Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Thu, 2 Oct 2025 21:20:14 -0400 Subject: [PATCH 1/4] Go 1.18 updates --- encode.go | 20 ++++++++++---------- encode_internal_test.go | 26 +++++++++++++------------- encode_test.go | 6 +++--- go.mod | 2 +- jsonstring.go | 2 +- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/encode.go b/encode.go index 42a71c8..d8f6935 100644 --- a/encode.go +++ b/encode.go @@ -13,7 +13,7 @@ import ( // MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence // of alternating keys and values. -func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) { +func MarshalKeyvals(keyvals ...any) ([]byte, error) { buf := &bytes.Buffer{} if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil { return nil, err @@ -45,7 +45,7 @@ var ( // EncodeKeyval writes the logfmt encoding of key and value to the stream. A // single space is written before the second and subsequent keys in a record. // Nothing is written if a non-nil error is returned. -func (enc *Encoder) EncodeKeyval(key, value interface{}) error { +func (enc *Encoder) EncodeKeyval(key, value any) error { enc.scratch.Reset() if enc.needSep { if _, err := enc.scratch.Write(space); err != nil { @@ -72,7 +72,7 @@ func (enc *Encoder) EncodeKeyval(key, value interface{}) error { // unsupported type or that cause a MarshalerError are replaced by their error // but do not cause EncodeKeyvals to return an error. If a non-nil error is // returned some key/value pairs may not have be written. -func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error { +func (enc *Encoder) EncodeKeyvals(keyvals ...any) error { if len(keyvals) == 0 { return nil } @@ -122,7 +122,7 @@ var ErrUnsupportedKeyType = errors.New("unsupported key type") // unsupported type. var ErrUnsupportedValueType = errors.New("unsupported value type") -func writeKey(w io.Writer, key interface{}) error { +func writeKey(w io.Writer, key any) error { if key == nil { return ErrNilKey } @@ -155,7 +155,7 @@ func writeKey(w io.Writer, key interface{}) error { switch rkey.Kind() { case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: return ErrUnsupportedKeyType - case reflect.Ptr: + case reflect.Pointer: if rkey.IsNil() { return ErrNilKey } @@ -194,7 +194,7 @@ func writeBytesKey(w io.Writer, key []byte) error { return err } -func writeValue(w io.Writer, value interface{}) error { +func writeValue(w io.Writer, value any) error { switch v := value.(type) { case nil: return writeBytesValue(w, null) @@ -222,7 +222,7 @@ func writeValue(w io.Writer, value interface{}) error { switch rvalue.Kind() { case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: return ErrUnsupportedValueType - case reflect.Ptr: + case reflect.Pointer: if rvalue.IsNil() { return writeBytesValue(w, null) } @@ -276,7 +276,7 @@ func (enc *Encoder) Reset() { func safeError(err error) (s string, ok bool) { defer func() { if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(err); v.Kind() == reflect.Pointer && v.IsNil() { s, ok = "null", false } else { s, ok = fmt.Sprintf("PANIC:%v", panicVal), false @@ -290,7 +290,7 @@ func safeError(err error) (s string, ok bool) { func safeString(str fmt.Stringer) (s string, ok bool) { defer func() { if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(str); v.Kind() == reflect.Pointer && v.IsNil() { s, ok = "null", false } else { s, ok = fmt.Sprintf("PANIC:%v", panicVal), true @@ -304,7 +304,7 @@ func safeString(str fmt.Stringer) (s string, ok bool) { func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) { defer func() { if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(tm); v.Kind() == reflect.Pointer && v.IsNil() { b, err = nil, nil } else { b, err = nil, fmt.Errorf("panic when marshalling: %s", panicVal) diff --git a/encode_internal_test.go b/encode_internal_test.go index 926c201..2d8665c 100644 --- a/encode_internal_test.go +++ b/encode_internal_test.go @@ -29,23 +29,23 @@ func TestSafeMarshal(t *testing.T) { func TestWriteKeyStrings(t *testing.T) { keygen := []struct { name string - fn func(string) interface{} + fn func(string) any }{ { name: "string", - fn: func(s string) interface{} { return s }, + fn: func(s string) any { return s }, }, { name: "named-string", - fn: func(s string) interface{} { return stringData(s) }, + fn: func(s string) any { return stringData(s) }, }, { name: "Stringer", - fn: func(s string) interface{} { return stringStringer(s) }, + fn: func(s string) any { return stringStringer(s) }, }, { name: "TextMarshaler", - fn: func(s string) interface{} { return stringMarshaler(s) }, + fn: func(s string) any { return stringMarshaler(s) }, }, } @@ -99,7 +99,7 @@ func TestWriteKey(t *testing.T) { ) data := []struct { - key interface{} + key any want string err error }{ @@ -135,12 +135,12 @@ func TestWriteKey(t *testing.T) { } func TestWriteValueStrings(t *testing.T) { - keygen := []func(string) interface{}{ - func(s string) interface{} { return s }, - func(s string) interface{} { return errors.New(s) }, - func(s string) interface{} { return stringData(s) }, - func(s string) interface{} { return stringStringer(s) }, - func(s string) interface{} { return stringMarshaler(s) }, + keygen := []func(string) any{ + func(s string) any { return s }, + func(s string) any { return errors.New(s) }, + func(s string) any { return stringData(s) }, + func(s string) any { return stringStringer(s) }, + func(s string) any { return stringMarshaler(s) }, } data := []struct { @@ -188,7 +188,7 @@ func TestWriteValue(t *testing.T) { ) data := []struct { - value interface{} + value any want string err error }{ diff --git a/encode_test.go b/encode_test.go index 29ef3c0..4591f83 100644 --- a/encode_test.go +++ b/encode_test.go @@ -14,7 +14,7 @@ import ( func TestEncodeKeyval(t *testing.T) { data := []struct { - key, value interface{} + key, value any want string err error }{ @@ -83,7 +83,7 @@ func TestMarshalKeyvals(t *testing.T) { nilPtr := (*int)(nil) data := []struct { - in []interface{} + in []any want []byte err error }{ @@ -146,7 +146,7 @@ func TestMarshalKeyvals(t *testing.T) { } } -func kv(keyvals ...interface{}) []interface{} { +func kv(keyvals ...any) []any { return keyvals } diff --git a/go.mod b/go.mod index c6fe10b..d910b1f 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/go-logfmt/logfmt -go 1.17 +go 1.18 diff --git a/jsonstring.go b/jsonstring.go index 4550cb3..26e1b1c 100644 --- a/jsonstring.go +++ b/jsonstring.go @@ -19,7 +19,7 @@ import ( var hex = "0123456789abcdef" var bufferPool = sync.Pool{ - New: func() interface{} { + New: func() any { return &bytes.Buffer{} }, } From 7302f2efece70e205460bade0c4e87e96814794e Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Sun, 5 Oct 2025 12:09:32 -0400 Subject: [PATCH 2/4] Go 1.19 updates --- encode_internal_test.go | 4 ++-- encode_test.go | 4 ++-- go.mod | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/encode_internal_test.go b/encode_internal_test.go index 2d8665c..c0ddec4 100644 --- a/encode_internal_test.go +++ b/encode_internal_test.go @@ -4,7 +4,7 @@ import ( "bytes" "errors" "fmt" - "io/ioutil" + "io" "reflect" "testing" ) @@ -266,7 +266,7 @@ func BenchmarkWriteStringKey(b *testing.B) { for _, k := range keys { b.Run(k, func(b *testing.B) { for i := 0; i < b.N; i++ { - writeStringKey(ioutil.Discard, k) + writeStringKey(io.Discard, k) } }) } diff --git a/encode_test.go b/encode_test.go index 4591f83..c09f729 100644 --- a/encode_test.go +++ b/encode_test.go @@ -4,7 +4,7 @@ import ( "bytes" "errors" "fmt" - "io/ioutil" + "io" "reflect" "testing" "time" @@ -220,7 +220,7 @@ func (p panicingStringer) String() string { func BenchmarkEncodeKeyval(b *testing.B) { b.ReportAllocs() - enc := logfmt.NewEncoder(ioutil.Discard) + enc := logfmt.NewEncoder(io.Discard) for i := 0; i < b.N; i++ { enc.EncodeKeyval("sk", "10") enc.EncodeKeyval("some-key", "a rather long string with spaces") diff --git a/go.mod b/go.mod index d910b1f..b8bc77b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,4 @@ module github.com/go-logfmt/logfmt -go 1.18 +go 1.19 + From 49db0db4f387a6d212388d01670881bde76cc066 Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Sun, 5 Oct 2025 12:14:52 -0400 Subject: [PATCH 3/4] Stop using reflect.DeepEqual for testing error values --- decode_test.go | 52 ++++++++++++++++++++++++------ encode_internal_test.go | 71 +++++++++++++++++++++++++++++++++++++---- go.mod | 1 + go.sum | 2 ++ 4 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 go.sum diff --git a/decode_test.go b/decode_test.go index 9d85ec4..0ec8a00 100644 --- a/decode_test.go +++ b/decode_test.go @@ -7,6 +7,9 @@ import ( "reflect" "strings" "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" ) type kv struct { @@ -155,6 +158,35 @@ func TestDecoder_scan(t *testing.T) { } func TestDecoder_errors(t *testing.T) { + tests := []struct { + data string + dec func(string) *Decoder + want error + }{ + { + data: "a=1\nb=2", + dec: func(s string) *Decoder { + dec := NewDecoderSize(strings.NewReader(s), 1) + return dec + }, + want: bufio.ErrTooLong, + }, + } + + for _, test := range tests { + dec := test.dec(test.data) + + for dec.ScanRecord() { + for dec.ScanKeyval() { + } + } + if diff := cmp.Diff(test.want, dec.Err(), cmpopts.EquateErrors()); diff != "" { + t.Errorf("%#v: Decoder.Err() value mismatch (-want,+got):\n%s", test.data, diff) + } + } +} + +func TestDecoder_SyntaxError(t *testing.T) { defaultDecoder := func(s string) *Decoder { return NewDecoder(strings.NewReader(s)) } tests := []struct { data string @@ -231,14 +263,6 @@ func TestDecoder_errors(t *testing.T) { dec: defaultDecoder, want: &SyntaxError{Msg: "invalid key", Line: 1, Pos: 2}, }, - { - data: "a=1\nb=2", - dec: func(s string) *Decoder { - dec := NewDecoderSize(strings.NewReader(s), 1) - return dec - }, - want: bufio.ErrTooLong, - }, } for _, test := range tests { @@ -248,8 +272,16 @@ func TestDecoder_errors(t *testing.T) { for dec.ScanKeyval() { } } - if got, want := dec.Err(), test.want; !reflect.DeepEqual(got, want) { - t.Errorf("got: %v, want: %v", got, want) + + switch got := dec.Err().(type) { + case nil: + t.Errorf("%#v: dec.Err() == nil, want: *SyntaxError", test.data) + case *SyntaxError: + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("%#v: dec.Err() mismatch (-want,+got):\n%s", test.data, diff) + } + default: + t.Errorf("%#v: dec.Err().(type) == %T, want: *SyntaxError", test.data, got) } } } diff --git a/encode_internal_test.go b/encode_internal_test.go index c0ddec4..ee6ca83 100644 --- a/encode_internal_test.go +++ b/encode_internal_test.go @@ -7,6 +7,9 @@ import ( "io" "reflect" "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" ) func TestSafeString(t *testing.T) { @@ -110,7 +113,6 @@ func TestWriteKey(t *testing.T) { {key: (*stringerMarshaler)(nil), err: ErrNilKey}, {key: ptr, want: "1"}, - {key: errorMarshaler{}, err: &MarshalerError{Type: reflect.TypeOf(errorMarshaler{}), Err: errMarshaling}}, {key: make(chan int), err: ErrUnsupportedKeyType}, {key: []int{}, err: ErrUnsupportedKeyType}, {key: map[int]int{}, err: ErrUnsupportedKeyType}, @@ -122,8 +124,8 @@ func TestWriteKey(t *testing.T) { for _, d := range data { w := &bytes.Buffer{} err := writeKey(w, d.key) - if !reflect.DeepEqual(err, d.err) { - t.Errorf("%#v: got error: %v, want error: %v", d.key, err, d.err) + if diff := cmp.Diff(d.err, err, cmpopts.EquateErrors()); diff != "" { + t.Errorf("%#v: error value mismatch (-want,+got):\n%s", d.key, diff) } if err != nil { continue @@ -134,6 +136,35 @@ func TestWriteKey(t *testing.T) { } } +func TestWriteKeyMarshalError(t *testing.T) { + data := []struct { + key any + want string + err error + }{ + {key: errorMarshaler{}, err: &MarshalerError{Type: reflect.TypeOf(errorMarshaler{}), Err: errMarshaling}}, + } + + for _, d := range data { + w := &bytes.Buffer{} + err := writeKey(w, d.key) + + switch err := err.(type) { + case nil: + t.Errorf("%#v: err == nil, want: not nil", d.key) + case *MarshalerError: + if got, want := err.Type, reflect.TypeOf(errorMarshaler{}); got != want { + t.Errorf("%#v: MarshalerError.Type == %v, want: %v", d.key, got, want) + } + if diff := cmp.Diff(errMarshaling, err.Err, cmpopts.EquateErrors()); diff != "" { + t.Errorf("%#v: MarshalerError.Err value mismatch (-want,+got):\n%s", d.key, diff) + } + default: + t.Errorf("%#v: unexpected error, got: %q, want: a MarshalerError", d.key, err) + } + } +} + func TestWriteValueStrings(t *testing.T) { keygen := []func(string) any{ func(s string) any { return s }, @@ -199,7 +230,6 @@ func TestWriteValue(t *testing.T) { {value: (*stringerMarshaler)(nil), want: "null"}, {value: ptr, want: "1"}, - {value: errorMarshaler{}, err: &MarshalerError{Type: reflect.TypeOf(errorMarshaler{}), Err: errMarshaling}}, {value: make(chan int), err: ErrUnsupportedValueType}, {value: []int{}, err: ErrUnsupportedValueType}, {value: map[int]int{}, err: ErrUnsupportedValueType}, @@ -211,8 +241,8 @@ func TestWriteValue(t *testing.T) { for _, d := range data { w := &bytes.Buffer{} err := writeValue(w, d.value) - if !reflect.DeepEqual(err, d.err) { - t.Errorf("%#v: got error: %v, want error: %v", d.value, err, d.err) + if diff := cmp.Diff(d.err, err, cmpopts.EquateErrors()); diff != "" { + t.Errorf("%#v: error value mismatch (-want,+got):\n%s", d.value, diff) } if err != nil { continue @@ -223,6 +253,35 @@ func TestWriteValue(t *testing.T) { } } +func TestWriteValueMarshalError(t *testing.T) { + data := []struct { + value any + want string + err error + }{ + {value: errorMarshaler{}, err: &MarshalerError{Type: reflect.TypeOf(errorMarshaler{}), Err: errMarshaling}}, + } + + for _, d := range data { + w := &bytes.Buffer{} + err := writeValue(w, d.value) + + switch err := err.(type) { + case nil: + t.Errorf("%#v: err == nil, want: not nil", d.value) + case *MarshalerError: + if got, want := err.Type, reflect.TypeOf(errorMarshaler{}); got != want { + t.Errorf("%#v: MarshalerError.Type == %v, want: %v", d.value, got, want) + } + if diff := cmp.Diff(errMarshaling, err.Err, cmpopts.EquateErrors()); diff != "" { + t.Errorf("%#v: MarshalerError.Err value mismatch (-want,+got):\n%s", d.value, diff) + } + default: + t.Errorf("%#v: unexpected error, got: %q, want: a MarshalerError", d.value, err) + } + } +} + type stringData string type stringStringer string diff --git a/go.mod b/go.mod index b8bc77b..9525d5b 100644 --- a/go.mod +++ b/go.mod @@ -2,3 +2,4 @@ module github.com/go-logfmt/logfmt go 1.19 +require github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= From c00d4c093132a161b31b1c868ec20eb7ce6fbab1 Mon Sep 17 00:00:00 2001 From: Chris Hines Date: Sun, 5 Oct 2025 12:27:55 -0400 Subject: [PATCH 4/4] go get github.com/google/go-cmp/cmp@latest --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 9525d5b..8adccb0 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/go-logfmt/logfmt -go 1.19 +go 1.21 -require github.com/google/go-cmp v0.6.0 +require github.com/google/go-cmp v0.7.0 diff --git a/go.sum b/go.sum index 5a8d551..40e761a 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,2 @@ -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=