package format import ( "strings" "testing" ) func TestParseBlockHeader(t *testing.T) { tests := []struct { line string wantNil bool wantRole string wantName string wantID string }{ // Valid headers {"[[[user]]]", false, "user", "", ""}, {"[[[user#abc12345]]]", false, "user", "", "abc12345"}, {"[[[assistant]]]", false, "assistant", "", ""}, {"[[[assistant#def67890]]]", false, "assistant", "", "def67890"}, {"[[[assistant:resp_123#aabbccdd]]]", false, "assistant", "resp_123", "aabbccdd"}, {"[[[tool:shell]]]", false, "tool", "shell", ""}, {"[[[tool:shell#11223344]]]", false, "tool", "shell", "11223344"}, {"[[[call:file_read]]]", false, "call", "file_read", ""}, {"[[[call:file_read#99887766]]]", false, "call", "file_read", "99887766"}, {"[[[reasoning]]]", false, "reasoning", "", ""}, {"[[[reasoning#aabbcc00]]]", false, "reasoning", "", "aabbcc00"}, {"[[[retry]]]", false, "retry", "", ""}, {"[[[end]]]", false, "end", "", ""}, {"[[[error]]]", false, "error", "", ""}, {"[[[error:file_read#12345678]]]", false, "error", "file_read", "12345678"}, {"[[[info]]]", false, "info", "", ""}, {"[[[stalled]]]", false, "stalled", "", ""}, // Invalid headers {"", true, "", "", ""}, {"[[[]]]", true, "", "", ""}, {"not a header", true, "", "", ""}, {"[[user]]", true, "", "", ""}, {"[[[user", true, "", "", ""}, {"user]]]", true, "", "", ""}, } for _, tt := range tests { bh := ParseBlockHeader(tt.line) if tt.wantNil { if bh != nil { t.Errorf("ParseBlockHeader(%q): expected nil, got %+v", tt.line, bh) } continue } if bh == nil { t.Errorf("ParseBlockHeader(%q): expected non-nil", tt.line) continue } if bh.Role != tt.wantRole { t.Errorf("ParseBlockHeader(%q): role = %q, want %q", tt.line, bh.Role, tt.wantRole) } if bh.Name != tt.wantName { t.Errorf("ParseBlockHeader(%q): name = %q, want %q", tt.line, bh.Name, tt.wantName) } if bh.BlockID != tt.wantID { t.Errorf("ParseBlockHeader(%q): blockID = %q, want %q", tt.line, bh.BlockID, tt.wantID) } } } func TestBlockDelim(t *testing.T) { tests := []struct { role, name, blockID string want string }{ {"user", "", "abc12345", "[[[user#abc12345]]]\n"}, {"assistant", "", "def67890", "[[[assistant#def67890]]]\n"}, {"tool", "shell", "11223344", "[[[tool:shell#11223344]]]\n"}, {"call", "file_read", "99887766", "[[[call:file_read#99887766]]]\n"}, {"error", "test", "aabbccdd", "[[[error:test#aabbccdd]]]\n"}, } for _, tt := range tests { got := BlockDelim(tt.role, tt.name, tt.blockID) if got != tt.want { t.Errorf("BlockDelim(%q, %q, %q) = %q, want %q", tt.role, tt.name, tt.blockID, got, tt.want) } } } func TestFormatEvent_WithBlockID(t *testing.T) { tests := []struct { role, name, content, outputFormat, blockID string wantContains []string }{ { "user", "", "hello", "", "abc12345", []string{"[[[user#abc12345]]]", "hello", "[[[end]]]"}, }, { "call", "shell", `{"cmd": "ls"}`, "", "def67890", []string{"[[[call:shell#def67890]]]", `{"cmd": "ls"}`, "[[[end]]]"}, }, { "tool", "shell", "output", "text", "11223344", []string{"[[[tool:shell#11223344]]]", "output", "[[[end]]]"}, }, { "error", "", "something failed", "", "aabbccdd", []string{"[[[error#aabbccdd]]]", "something failed", "[[[end]]]"}, }, { "error", "test", "something failed", "", "eeff0011", []string{"[[[error:test#eeff0011]]]", "something failed", "[[[end]]]"}, }, { "info", "", "status update", "", "22334455", []string{"[[[info#22334455]]]", "status update", "[[[end]]]"}, }, { "stalled", "", "", "", "66778899", []string{"[[[stalled#66778899]]]", "[[[end]]]"}, }, { "maxsteps", "", "limit reached", "", "aabbcc00", []string{"[[[maxsteps#aabbcc00]]]", "limit reached", "[[[end]]]"}, }, } for _, tt := range tests { got := string(FormatEvent(tt.role, tt.name, tt.content, tt.outputFormat, tt.blockID)) for _, want := range tt.wantContains { if !strings.Contains(got, want) { t.Errorf("FormatEvent(%q, %q, ...): missing %q in:\n%s", tt.role, tt.name, want, got) } } } } func TestIsEndMarker(t *testing.T) { tests := []struct { line string want bool }{ {"[[[end]]]", true}, {"[[[end]]", false}, {"[[end]]]", false}, {"[[[END]]]", false}, {"[[[end]]] ", false}, {" [[[end]]]", false}, {"", false}, } for _, tt := range tests { got := IsEndMarker(tt.line) if got != tt.want { t.Errorf("IsEndMarker(%q) = %v, want %v", tt.line, got, tt.want) } } } func TestRoundtrip_ParseBlockHeader(t *testing.T) { // Test that BlockDelim output can be parsed by ParseBlockHeader tests := []struct { role, name, blockID string }{ {"user", "", "abc12345"}, {"tool", "shell", "def67890"}, {"call", "file_read", "11223344"}, } for _, tt := range tests { delim := BlockDelim(tt.role, tt.name, tt.blockID) // Trim the trailing newline for parsing delim = strings.TrimSuffix(delim, "\n") bh := ParseBlockHeader(delim) if bh == nil { t.Errorf("ParseBlockHeader(BlockDelim(%q, %q, %q)) returned nil", tt.role, tt.name, tt.blockID) continue } if bh.Role != tt.role { t.Errorf("roundtrip role: got %q, want %q", bh.Role, tt.role) } if bh.Name != tt.name { t.Errorf("roundtrip name: got %q, want %q", bh.Name, tt.name) } if bh.BlockID != tt.blockID { t.Errorf("roundtrip blockID: got %q, want %q", bh.BlockID, tt.blockID) } } }