package lambdalog
import (
"encoding/json"
"errors"
"strings"
"testing"
"time"
)
func TestEncodeValue_Primitives(t *testing.T) {
t.Parallel()
cases := []struct {
name string
in any
want string
}{
{"nil", nil, "null"},
{"bool-true", true, "true"},
{"bool-false", false, "false"},
{"int", 42, "42"},
{"int64-neg", int64(-7), "-7"},
{"uint", uint(9), "9"},
{"float", 1.5, "1.5"},
{"string-plain", "hello", `"hello"`},
{"string-escape", "line\nbreak", `"line\nbreak"`},
{"string-quote", `he said "hi"`, `"he said \"hi\""`},
{"bytes", []byte("abc"), `"abc"`},
{"duration", 250 * time.Millisecond, `"250ms"`},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got := string(encodeValue(nil, tc.in))
if got != tc.want {
t.Fatalf("encodeValue(%v) = %s, want %s", tc.in, got, tc.want)
}
})
}
}
func TestEncodeValue_ErrorRendersMessage(t *testing.T) {
t.Parallel()
err := errors.New("disk full")
got := string(encodeValue(nil, err))
if got != `"disk full"` {
t.Fatalf("unexpected: %s", got)
}
}
func TestEncodeValue_MapIsSorted(t *testing.T) {
t.Parallel()
m := map[string]any{"zeta": 1, "alpha": 2, "mu": 3}
got := string(encodeValue(nil, m))
want := `{"alpha":2,"mu":3,"zeta":1}`
if got != want {
t.Fatalf("map encoding not sorted: %s", got)
}
}
func TestEncodeValue_FallsBackToStdJSON(t *testing.T) {
t.Parallel()
type custom struct {
A int `json:"a"`
B string `json:"b"`
}
got := string(encodeValue(nil, custom{A: 1, B: "two"}))
var rt custom
if err := json.Unmarshal([]byte(got), &rt); err != nil {
t.Fatalf("fallback produced invalid JSON: %v (%s)", err, got)
}
if rt.A != 1 || rt.B != "two" {
t.Fatalf("fallback round-trip failed: %+v", rt)
}
}
func TestEncodeRecord_IsSingleJSONLine(t *testing.T) {
t.Parallel()
line := encodeRecord(LevelInfo, "hi", []attr{{Key: "user", Value: "bob"}}, []any{"n", 3})
if !strings.HasSuffix(string(line), "\n") {
t.Fatal("encoded record should end with newline")
}
var rec map[string]any
if err := json.Unmarshal(line[:len(line)-1], &rec); err != nil {
t.Fatalf("record is not valid JSON: %v (%s)", err, line)
}
if rec["level"] != "info" || rec["msg"] != "hi" || rec["user"] != "bob" {
t.Fatalf("unexpected decoded record: %+v", rec)
}
}
func TestAppendQuoted_ControlCharacters(t *testing.T) {
t.Parallel()
got := string(appendQuoted(nil, "a\x01b"))
if !strings.Contains(got, ``) {
t.Fatalf("expected \\u0001 escape, got %s", got)
}
}
func TestSortStrings(t *testing.T) {
t.Parallel()
xs := []string{"c", "a", "b", "a"}
sortStrings(xs)
want := []string{"a", "a", "b", "c"}
for i := range want {
if xs[i] != want[i] {
t.Fatalf("sortStrings result: %v", xs)
}
}
}