From 33ca94e2f1fe84809d585035b3b13ea3eaf06702 Mon Sep 17 00:00:00 2001 From: liujing Date: Sun, 22 Mar 2026 21:38:27 +0800 Subject: [PATCH] test(opencode): add regression tests for session list parsing (#262) Add two focused tests to prevent regression: 1. TestOpencodeSessionEntry_Unmarshal - verifies OpenCode's JSON output with int64 timestamps can be unmarshaled (prevents the type mismatch error: cannot unmarshal number into ... of type string) 2. TestNewOpencodeSession_ContinueSessionTreatedAsFresh - verifies the __continue__ sentinel is not passed as literal session ID to CLI (regression test for PR #249) Co-authored-by: Liujing Co-authored-by: Claude Opus 4.6 --- agent/opencode/session_test.go | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 agent/opencode/session_test.go diff --git a/agent/opencode/session_test.go b/agent/opencode/session_test.go new file mode 100644 index 0000000..e3d2bc5 --- /dev/null +++ b/agent/opencode/session_test.go @@ -0,0 +1,71 @@ +package opencode + +import ( + "context" + "encoding/json" + "testing" + + "github.com/chenhg5/cc-connect/core" +) + +// TestOpencodeSessionEntry_Unmarshal verifies that OpenCode's +// `session list --format json` output can be correctly parsed. +// +// OpenCode returns `updated` and `created` as Unix timestamps in +// milliseconds (int64), not strings. This test prevents regression +// of the unmarshal error: +// +// json: cannot unmarshal number into Go struct field opencodeSessionEntry.updated of type string +func TestOpencodeSessionEntry_Unmarshal(t *testing.T) { + jsonData := `[ + { + "id": "ses_2eb11bb11ffeYwQZOj25mlmGMc", + "title": "Test Session", + "updated": 1774174646445, + "created": 1774172652782, + "projectId": "b80385ead03e8b450bdb2016d434aad318f93c16", + "directory": "/path/to/project" + } +]` + + var entries []opencodeSessionEntry + if err := json.Unmarshal([]byte(jsonData), &entries); err != nil { + t.Fatalf("Failed to unmarshal OpenCode session list: %v", err) + } + + if len(entries) != 1 { + t.Fatalf("Expected 1 entry, got %d", len(entries)) + } + + e := entries[0] + if e.ID != "ses_2eb11bb11ffeYwQZOj25mlmGMc" { + t.Errorf("ID = %q, want %q", e.ID, "ses_2eb11bb11ffeYwQZOj25mlmGMc") + } + if e.Title != "Test Session" { + t.Errorf("Title = %q, want %q", e.Title, "Test Session") + } + if e.Updated != 1774174646445 { + t.Errorf("Updated = %d, want %d", e.Updated, 1774174646445) + } + if e.Created != 1774172652782 { + t.Errorf("Created = %d, want %d", e.Created, 1774172652782) + } +} + +// TestNewOpencodeSession_ContinueSessionTreatedAsFresh verifies that +// the ContinueSession sentinel (__continue__) is not passed as a literal +// session ID to the CLI. This was fixed in PR #249. +func TestNewOpencodeSession_ContinueSessionTreatedAsFresh(t *testing.T) { + s, err := newOpencodeSession(context.Background(), "echo", "/tmp", "", "default", core.ContinueSession, nil) + if err != nil { + t.Fatalf("newOpencodeSession: %v", err) + } + defer s.Close() + + if got := s.CurrentSessionID(); got != "" { + t.Errorf("ContinueSession should be treated as fresh: chatID = %q, want empty", got) + } +} + +// verify Agent implements core.Agent +var _ core.Agent = (*Agent)(nil)