package json_test
import (
"bytes"
stdjson "encoding/json"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"mercemay.top/src/lambdalog/internal/encoder"
logjson "mercemay.top/src/lambdalog/internal/encoder/json"
)
func TestEncoder_Name(t *testing.T) {
if got := (logjson.Encoder{}).Name(); got != "json" {
t.Fatalf("Name = %q, want json", got)
}
}
func TestEncoder_Encode(t *testing.T) {
cases := []struct {
name string
rec encoder.Record
want map[string]any
}{
{
name: "basic",
rec: encoder.Record{
Time: time.Date(2024, 10, 1, 12, 0, 0, 0, time.UTC),
Level: "info",
Message: "hello",
},
want: map[string]any{
"time": "2024-10-01T12:00:00Z",
"level": "info",
"msg": "hello",
},
},
{
name: "with-request-id-and-fields",
rec: encoder.Record{
Time: time.Date(2024, 10, 1, 12, 0, 0, 0, time.UTC),
Level: "error",
Message: "boom",
RequestID: "req-1",
Fields: []encoder.Field{
{Key: "count", Value: int64(3)},
{Key: "ok", Value: false},
},
},
want: map[string]any{
"time": "2024-10-01T12:00:00Z",
"level": "error",
"msg": "boom",
"request_id": "req-1",
"count": float64(3),
"ok": false,
},
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Helper()
var buf bytes.Buffer
if err := (logjson.Encoder{}).Encode(&buf, tc.rec); err != nil {
t.Fatalf("encode: %v", err)
}
if !strings.HasSuffix(buf.String(), "\n") {
t.Fatalf("missing trailing newline: %q", buf.String())
}
got := map[string]any{}
if err := stdjson.Unmarshal(buf.Bytes(), &got); err != nil {
t.Fatalf("parse: %v: %s", err, buf.String())
}
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Fatalf("record (-want +got):\n%s", diff)
}
})
}
}
func TestEncoder_EscapesQuotes(t *testing.T) {
var buf bytes.Buffer
rec := encoder.Record{Message: `he said "hi"`, Level: "info", Time: time.Unix(0, 0).UTC()}
if err := (logjson.Encoder{}).Encode(&buf, rec); err != nil {
t.Fatalf("encode: %v", err)
}
out := map[string]any{}
if err := stdjson.Unmarshal(buf.Bytes(), &out); err != nil {
t.Fatalf("parse: %v", err)
}
if out["msg"] != `he said "hi"` {
t.Fatalf("round-trip lost quoting: %#v", out["msg"])
}
}
func TestEncoder_TimeFormatOverride(t *testing.T) {
enc := logjson.Encoder{TimeFormat: time.RFC3339}
var buf bytes.Buffer
rec := encoder.Record{Time: time.Date(2024, 1, 2, 3, 4, 5, 999, time.UTC), Level: "info", Message: "x"}
if err := enc.Encode(&buf, rec); err != nil {
t.Fatalf("encode: %v", err)
}
if !strings.Contains(buf.String(), "2024-01-02T03:04:05Z") {
t.Fatalf("expected RFC3339 time, got %s", buf.String())
}
}