Files
cc-connect/core/progress_compact_test.go
T
Jerry bfb6d69780 Feature: normalize local references for IM rendering and add /show for direct file inspection (#495)
* feat(references): normalize and render local agent references

* feat(show): add reference-aware file and directory viewing

* docs: document references config and show usage

* chore: remove local working docs from PR branch

* fix: address lint issues in reference pipeline

* fix: drop stale quiet leftovers after main rebase

* fix: clean remaining rebase markers in show tests
2026-04-09 16:50:25 +08:00

182 lines
6.5 KiB
Go

package core
import (
"context"
"strings"
"testing"
)
type suppressTestPlatform struct {
style string
}
func (s *suppressTestPlatform) Name() string { return "test" }
func (s *suppressTestPlatform) Start(MessageHandler) error { return nil }
func (s *suppressTestPlatform) Reply(context.Context, any, string) error { return nil }
func (s *suppressTestPlatform) Send(context.Context, any, string) error { return nil }
func (s *suppressTestPlatform) Stop() error { return nil }
func (s *suppressTestPlatform) ProgressStyle() string { return s.style }
func TestSuppressStandaloneToolResultEvent(t *testing.T) {
if SuppressStandaloneToolResultEvent(&stubPlatformNoProgress{}) {
t.Fatal("platform without ProgressStyleProvider should not suppress")
}
if !SuppressStandaloneToolResultEvent(&suppressTestPlatform{style: "legacy"}) {
t.Fatal("legacy ProgressStyleProvider should suppress standalone tool results")
}
if SuppressStandaloneToolResultEvent(&suppressTestPlatform{style: "compact"}) {
t.Fatal("compact should not suppress (writer absorbs tool results)")
}
if SuppressStandaloneToolResultEvent(&suppressTestPlatform{style: "card"}) {
t.Fatal("card should not suppress")
}
}
// stubPlatformNoProgress is a minimal Platform without ProgressStyleProvider.
type stubPlatformNoProgress struct{}
func (stubPlatformNoProgress) Name() string { return "plain" }
func (stubPlatformNoProgress) Start(MessageHandler) error { return nil }
func (stubPlatformNoProgress) Reply(context.Context, any, string) error { return nil }
func (stubPlatformNoProgress) Send(context.Context, any, string) error { return nil }
func (stubPlatformNoProgress) Stop() error { return nil }
func TestBuildAndParseProgressCardPayload(t *testing.T) {
payload := BuildProgressCardPayload([]string{" step1 ", "", "step2"}, true)
if payload == "" {
t.Fatal("BuildProgressCardPayload returned empty string")
}
if !strings.HasPrefix(payload, ProgressCardPayloadPrefix) {
t.Fatalf("payload = %q, want prefix %q", payload, ProgressCardPayloadPrefix)
}
parsed, ok := ParseProgressCardPayload(payload)
if !ok {
t.Fatalf("ParseProgressCardPayload should succeed, payload=%q", payload)
}
if len(parsed.Entries) != 2 {
t.Fatalf("entries = %d, want 2", len(parsed.Entries))
}
if parsed.Entries[0] != "step1" || parsed.Entries[1] != "step2" {
t.Fatalf("entries = %#v, want [step1 step2]", parsed.Entries)
}
if !parsed.Truncated {
t.Fatal("parsed.Truncated = false, want true")
}
if len(parsed.Items) != 2 {
t.Fatalf("items = %d, want 2", len(parsed.Items))
}
if parsed.Items[0].Kind != ProgressEntryInfo || parsed.Items[0].Text != "step1" {
t.Fatalf("items[0] = %#v, want info/step1", parsed.Items[0])
}
}
func TestBuildAndParseProgressCardPayloadV2(t *testing.T) {
payload := BuildProgressCardPayloadV2([]ProgressCardEntry{
{Kind: ProgressEntryThinking, Text: " plan "},
{Kind: ProgressEntryToolUse, Tool: "Bash", Text: "pwd"},
}, false, "Codex", LangChinese, ProgressCardStateRunning)
if payload == "" {
t.Fatal("BuildProgressCardPayloadV2 returned empty string")
}
parsed, ok := ParseProgressCardPayload(payload)
if !ok {
t.Fatalf("ParseProgressCardPayload should succeed, payload=%q", payload)
}
if parsed.Version != 2 {
t.Fatalf("version = %d, want 2", parsed.Version)
}
if parsed.Agent != "Codex" {
t.Fatalf("agent = %q, want Codex", parsed.Agent)
}
if parsed.Lang != string(LangChinese) {
t.Fatalf("lang = %q, want %q", parsed.Lang, LangChinese)
}
if parsed.State != ProgressCardStateRunning {
t.Fatalf("state = %q, want %q", parsed.State, ProgressCardStateRunning)
}
if len(parsed.Items) != 2 {
t.Fatalf("items = %d, want 2", len(parsed.Items))
}
if parsed.Items[1].Kind != ProgressEntryToolUse || parsed.Items[1].Tool != "Bash" {
t.Fatalf("items[1] = %#v, want tool_use/Bash", parsed.Items[1])
}
}
func TestParseProgressCardPayloadRejectsInvalid(t *testing.T) {
if _, ok := ParseProgressCardPayload("plain text"); ok {
t.Fatal("expected parse failure for plain text")
}
if _, ok := ParseProgressCardPayload(ProgressCardPayloadPrefix + "{not-json"); ok {
t.Fatal("expected parse failure for invalid json")
}
if _, ok := ParseProgressCardPayload(ProgressCardPayloadPrefix + `{"entries":[]}`); ok {
t.Fatal("expected parse failure for empty entries")
}
}
func TestCompactProgressWriter_AppliesTransformToCardPayloadEntries(t *testing.T) {
p := &stubCompactProgressPlatform{
stubPlatformEngine: stubPlatformEngine{n: "feishu"},
style: "card",
supportPayload: true,
}
w := newCompactProgressWriter(context.Background(), p, "ctx", "codex", LangEnglish, func(s string) string {
return strings.ReplaceAll(s, "/root/code/demo/src/app.ts:42", "📄 `src/app.ts:42`")
})
if ok := w.AppendStructured(ProgressCardEntry{
Kind: ProgressEntryThinking,
Text: "Inspect /root/code/demo/src/app.ts:42",
}, "Inspect /root/code/demo/src/app.ts:42"); !ok {
t.Fatal("AppendStructured() = false, want true")
}
starts := p.getPreviewStarts()
if len(starts) != 1 {
t.Fatalf("preview starts = %d, want 1", len(starts))
}
payload, ok := ParseProgressCardPayload(starts[0])
if !ok {
t.Fatalf("ParseProgressCardPayload(%q) failed", starts[0])
}
if len(payload.Items) != 1 {
t.Fatalf("payload items = %d, want 1", len(payload.Items))
}
if got := payload.Items[0].Text; got != "Inspect 📄 `src/app.ts:42`" {
t.Fatalf("payload item text = %q, want transformed text", got)
}
}
func TestCompactProgressWriter_DoesNotTransformToolResults(t *testing.T) {
p := &stubCompactProgressPlatform{
stubPlatformEngine: stubPlatformEngine{n: "feishu"},
style: "card",
supportPayload: true,
}
w := newCompactProgressWriter(context.Background(), p, "ctx", "codex", LangEnglish, func(s string) string {
return strings.ReplaceAll(s, "/root/code/demo/src/app.ts:42", "📄 `src/app.ts:42`")
})
raw := "/root/code/demo/src/app.ts:42"
if ok := w.AppendStructured(ProgressCardEntry{
Kind: ProgressEntryToolResult,
Text: raw,
}, raw); !ok {
t.Fatal("AppendStructured() = false, want true")
}
starts := p.getPreviewStarts()
if len(starts) != 1 {
t.Fatalf("preview starts = %d, want 1", len(starts))
}
payload, ok := ParseProgressCardPayload(starts[0])
if !ok {
t.Fatalf("ParseProgressCardPayload(%q) failed", starts[0])
}
if got := payload.Items[0].Text; got != raw {
t.Fatalf("tool result text = %q, want raw %q", got, raw)
}
}