internal/encoder/json/escape/html_test.go

package escape_test

import (
	stdjson "encoding/json"
	"strings"
	"testing"

	"mercemay.top/src/lambdalog/internal/encoder/json/escape"
	"mercemay.top/src/lambdalog/internal/encoder/json/fast"
)

func TestString_NoEscapeNeeded(t *testing.T) {
	b := fast.Get()
	t.Cleanup(func() { fast.Put(b) })
	escape.String(b, "hello world", false)
	if got := string(b.Bytes()); got != "hello world" {
		t.Fatalf("got %q", got)
	}
}

func TestString_Escapes(t *testing.T) {
	cases := []struct {
		name string
		in   string
		want string
	}{
		{"quote", `he "said"`, `he \"said\"`},
		{"backslash", `a\b`, `a\\b`},
		{"newline", "a\nb", `a\nb`},
		{"control", string([]byte{0x01}), ``},
		{"html-sensitive-off", "<a>&b", "<a>&b"},
	}
	for _, tc := range cases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Helper()
			b := fast.Get()
			t.Cleanup(func() { fast.Put(b) })
			escape.String(b, tc.in, false)
			if got := string(b.Bytes()); got != tc.want {
				t.Fatalf("got %q, want %q", got, tc.want)
			}
		})
	}
}

func TestString_HTMLMode(t *testing.T) {
	b := fast.Get()
	t.Cleanup(func() { fast.Put(b) })
	escape.String(b, "<a>&b", true)
	got := string(b.Bytes())
	for _, want := range []string{`<`, `>`, `&`} {
		if !strings.Contains(got, want) {
			t.Fatalf("html mode missing %s: %q", want, got)
		}
	}
}

func TestString_LineSeparatorEscaped(t *testing.T) {
	b := fast.Get()
	t.Cleanup(func() { fast.Put(b) })
	escape.String(b, "x
y", false)
	if !strings.Contains(string(b.Bytes()), `
`) {
		t.Fatalf("U+2028 not escaped: %q", b.Bytes())
	}
}

func TestString_IsValidJSON(t *testing.T) {
	b := fast.Get()
	t.Cleanup(func() { fast.Put(b) })
	b.AppendByte('"')
	escape.String(b, "control\x00tab\there\n", false)
	b.AppendByte('"')
	var out string
	if err := stdjson.Unmarshal(b.Bytes(), &out); err != nil {
		t.Fatalf("not valid JSON: %v: %q", err, b.Bytes())
	}
	if !strings.Contains(out, "control") {
		t.Fatalf("round trip lost content: %q", out)
	}
}

func TestBytes_SameAsString(t *testing.T) {
	a := fast.Get()
	t.Cleanup(func() { fast.Put(a) })
	bs := fast.Get()
	t.Cleanup(func() { fast.Put(bs) })
	escape.String(a, "plain \"text\"", false)
	escape.Bytes(bs, []byte("plain \"text\""), false)
	if string(a.Bytes()) != string(bs.Bytes()) {
		t.Fatalf("mismatch: %q vs %q", a.Bytes(), bs.Bytes())
	}
}