-
-
Save telemachus/d52423b7aae1c280bef44faa981225c9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tint_test | |
import ( | |
"bytes" | |
"fmt" | |
"log/slog" | |
"strings" | |
"testing" | |
"testing/slogtest" | |
"time" | |
"github.com/lmittmann/tint" | |
) | |
// This code is (very lightly) adapted from examples in slog and slogtest. | |
// Thanks to Jonathan Amsterdam for both. | |
func TestSlogtest(t *testing.T) { | |
t.Parallel() | |
var buf bytes.Buffer | |
opts := tint.Options{ | |
TimeFormat: time.Kitchen, | |
NoColor: true, | |
} | |
h := tint.NewHandler(&buf, &opts) | |
results := func() []map[string]any { | |
ms := []map[string]any{} | |
for _, line := range bytes.Split(buf.Bytes(), []byte{'\n'}) { | |
if len(line) == 0 { | |
continue | |
} | |
m, err := parseTint(line) | |
if err != nil { | |
t.Fatal(err) | |
} | |
ms = append(ms, m) | |
} | |
return ms | |
} | |
if err := slogtest.TestHandler(h, results); err != nil { | |
t.Error(err) | |
} | |
} | |
func parseTint(bs []byte) (map[string]any, error) { | |
top := map[string]any{} | |
s := string(bytes.TrimSpace(bs)) | |
// First, we need to divide each line into four parts (time, level, | |
// message, and kv pairs). The time portion of each line is optional. | |
// (The message portion can contain spaces, but slogtest only emits | |
// messages without spaces to make parsing easier.) | |
// Then we need to create proper key-value pairs for time (if present), | |
// level, and message. | |
pieces := strings.Split(s, " ") | |
firstKV := 3 | |
if _, err := time.Parse(time.Kitchen, pieces[0]); err == nil { | |
top[slog.TimeKey] = strings.TrimSpace(pieces[0]) | |
top[slog.LevelKey] = strings.TrimSpace(pieces[1]) | |
top[slog.MessageKey] = pieces[2] | |
} else { | |
top[slog.LevelKey] = strings.TrimSpace(pieces[0]) | |
top[slog.MessageKey] = pieces[1] | |
firstKV = 2 | |
} | |
// The rest of the line contains kv pairs that we can (roughly) divide | |
// by spaces. This is crude since it will split a quoted key or value | |
// that contains a space. For this test, however, this will work---as | |
// long as I make sure to set a time format without whitespace. | |
s = strings.Join(pieces[firstKV:], " ") | |
for len(s) > 0 { | |
kv, rest, _ := strings.Cut(s, " ") | |
k, value, found := strings.Cut(kv, "=") | |
if !found { | |
return nil, fmt.Errorf("no '=' in %q", kv) | |
} | |
keys := strings.Split(k, ".") | |
// Populate a tree of maps for a dotted path such as "a.b.c=x". | |
m := top | |
for _, key := range keys[:len(keys)-1] { | |
x, ok := m[key] | |
var m2 map[string]any | |
if !ok { | |
m2 = map[string]any{} | |
m[key] = m2 | |
} else { | |
m2, ok = x.(map[string]any) | |
if !ok { | |
return nil, fmt.Errorf("value for %q in composite key %q is not map[string]any", key, k) | |
} | |
} | |
m = m2 | |
} | |
m[keys[len(keys)-1]] = value | |
s = rest | |
} | |
return top, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment