blob: 9800ef741ed358d4092e435b7bb50ff0b6dedaf0 [file] [log] [blame]
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// TODO: verify that the output of Marshal{Text,JSON} is suitably escaped.
package slog
import (
"bytes"
"fmt"
"strings"
"testing"
"time"
"golang.org/x/exp/slog/internal/buffer"
)
func TestDefaultWith(t *testing.T) {
d := &defaultHandler{}
if g := len(d.attrs); g != 0 {
t.Errorf("got %d, want 0", g)
}
a1 := []Attr{Int("a", 1)}
d2 := d.With(a1)
if g := d2.(*defaultHandler).attrs; !attrsEqual(g, a1) {
t.Errorf("got %v, want %v", g, a1)
}
d3 := d2.With([]Attr{String("b", "two")})
want := append(a1, String("b", "two"))
if g := d3.(*defaultHandler).attrs; !attrsEqual(g, want) {
t.Errorf("got %v, want %v", g, want)
}
}
func TestCommonHandle(t *testing.T) {
tm := time.Date(2022, 9, 18, 8, 26, 33, 0, time.UTC)
r := NewRecord(tm, InfoLevel, "message", 1)
r.AddAttrs(String("a", "one"), Int("b", 2), Any("", "ignore me"))
for _, test := range []struct {
name string
h *commonHandler
want string
}{
{
name: "basic",
h: &commonHandler{},
want: "(time=2022-09-18T08:26:33.000Z;level=INFO;msg=message;a=one;b=2)",
},
{
name: "cap keys",
h: &commonHandler{
opts: HandlerOptions{ReplaceAttr: upperCaseKey},
},
want: "(TIME=2022-09-18T08:26:33.000Z;LEVEL=INFO;MSG=message;A=one;B=2)",
},
{
name: "remove all",
h: &commonHandler{
opts: HandlerOptions{
ReplaceAttr: func(a Attr) Attr { return Attr{} },
},
},
// TODO: fix this. The correct result is "()".
want: "(;;)",
},
} {
t.Run(test.name, func(t *testing.T) {
var buf bytes.Buffer
test.h.w = &buf
test.h.newAppender = func(buf *buffer.Buffer) appender {
return &testAppender{buf}
}
if err := test.h.handle(r); err != nil {
t.Fatal(err)
}
got := strings.TrimSuffix(buf.String(), "\n")
if got != test.want {
t.Errorf("\ngot %#v\nwant %#v\n", got, test.want)
}
})
}
}
func upperCaseKey(a Attr) Attr {
return a.WithKey(strings.ToUpper(a.Key()))
}
type testAppender struct {
buf *buffer.Buffer
}
func (a *testAppender) appendStart() { a.buf.WriteByte('(') }
func (a *testAppender) appendSep() { a.buf.WriteByte(';') }
func (a *testAppender) appendEnd() { a.buf.WriteByte(')') }
func (a *testAppender) appendKey(key string) {
a.appendString(key)
a.buf.WriteByte('=')
}
func (a *testAppender) appendString(s string) { a.buf.WriteString(s) }
func (a *testAppender) appendTime(t time.Time) error {
*a.buf = appendTimeRFC3339Millis(*a.buf, t)
return nil
}
func (a *testAppender) appendSource(file string, line int) {
a.appendString(fmt.Sprintf("%s:%d", file, line))
}
func (a *testAppender) appendAttrValue(at Attr) error {
switch at.Kind() {
case StringKind:
a.appendString(at.str())
case TimeKind:
a.appendTime(at.Time())
default:
*a.buf = at.appendValue(*a.buf)
}
return nil
}
const rfc3339Millis = "2006-01-02T15:04:05.000Z07:00"
func TestAppendTimeRFC3339(t *testing.T) {
for _, tm := range []time.Time{
time.Date(2000, 1, 2, 3, 4, 5, 0, time.UTC),
time.Date(2000, 1, 2, 3, 4, 5, 400, time.Local),
time.Date(2000, 11, 12, 3, 4, 500, 5e7, time.UTC),
} {
want := tm.Format(rfc3339Millis)
var buf []byte
buf = appendTimeRFC3339Millis(buf, tm)
got := string(buf)
if got != want {
t.Errorf("got %s, want %s", got, want)
}
}
}
func BenchmarkAppendTime(b *testing.B) {
buf := make([]byte, 0, 100)
tm := time.Date(2022, 3, 4, 5, 6, 7, 823456789, time.Local)
b.ResetTimer()
for i := 0; i < b.N; i++ {
buf = appendTimeRFC3339Millis(buf, tm)
buf = buf[:0]
}
}