Download
44 lines 1.5 KiBGoModified 2026-10-26 raw
1234567891011121314151617181920212223242526272829303132333435363738394041424344
package history

import (
	"reflect"
	"strings"
	"testing"
	"time"
	"unicode/utf8"
)

// xmlChar reports whether XML can hold a character.
func xmlChar(r rune) bool {
	return r == '\t' || r == '\n' || r == '\r' || r >= 0x20 && r <= 0xd7ff || r >= 0xe000 && r <= 0xfffd || r >= 0x10000 && r <= 0x10ffff
}

// A saved session always loads, and text XML can hold comes back exactly:
// the history is the record of what the model did.
func FuzzSaveLoad(f *testing.F) {
	f.Add("/p", "m", "hello", "", "id", "Read", `{"path":"a\r\nb"}`)
	f.Add("/p q", "m\x1b", "]]> <a> &amp; \x00", "\r", "\"", "<x>", "\xff")
	f.Fuzz(func(t *testing.T, project, model, content, reasoning, id, name, args string) {
		dir := t.TempDir()
		s := &Session{Project: project, Model: model, Started: time.Unix(1700000000, 0).UTC(), Messages: []Message{
			{Role: "user", Content: content},
			{Role: "assistant", Reasoning: reasoning, Content: content, ToolCalls: []ToolCall{{ID: id, Name: name, Arguments: args}}},
			{Role: "tool", ToolCallID: id, Content: args},
		}}
		if err := s.Save(dir); err != nil {
			t.Fatalf("Save: %v", err)
		}
		got, err := Load(s.Path(dir))
		if err != nil {
			t.Fatalf("Load: %v", err)
		}
		valid := true
		for _, v := range []string{project, model, content, reasoning, id, name, args} {
			valid = valid && utf8.ValidString(v) && !strings.ContainsFunc(v, func(r rune) bool { return !xmlChar(r) })
		}
		got.XMLName = s.XMLName // set by Unmarshal only
		if valid && !reflect.DeepEqual(got, s) {
			t.Fatalf("round trip:\n%+v\n%+v", s, got)
		}
	})
}