Files
AskaEth 95f97f5df3
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(comments): 注释中文化 · plugins/channels/weixin_ilink(20 文件,纯替换)
- 只翻注释/文档字符串:剥掉行尾注释后,每条「-」都有逐字节相同的「+」对应行(8 组,代码零改动)
- 保留协议/线上标识符原文:errcode、bot_token、context_token、getupdates、binded_redirect、PKCS#7、ECB 等
- 术语对齐既有译法:owner→主人、peer→对端、long poll→长轮询、backoff→退避、sentinel error→哨兵错误
- 已知既有欠债(未顺手修):login_reuse_test.go 在 HEAD 上就未 gofmt 干净;login_test.go 的 TestStartLogin_ScanStatusTransition 91 行 >80(HEAD 同为 91 行)
2026-10-04 12:29:05 +08:00

201 lines
6.0 KiB
Go

package weixin_ilink
import (
"context"
"errors"
"testing"
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
)
func TestAdapter_Name_And_DefaultCapabilities(t *testing.T) {
t.Parallel()
ad, err := New(Config{BaseURL: "https://ilinkai.weixin.qq.com"}, nil, nil)
if err != nil {
t.Fatalf("New: %v", err)
}
if got := ad.Name(); got != "weixin-ilink" {
t.Fatalf("Name() = %q, want weixin-ilink", got)
}
caps := ad.Capabilities()
if !caps.Proactive {
t.Error("Capabilities().Proactive = false, want true (iLink has a 24h window)")
}
if !caps.Image {
t.Error("Capabilities().Image = false, want true")
}
if got := caps.Normalize().MaxMessageLength; got <= 0 {
t.Fatalf("MaxMessageLength = %d, want > 0", got)
}
}
func TestAdapter_New_RejectsBadBaseURL(t *testing.T) {
t.Parallel()
_, err := New(Config{BaseURL: "not-a-url"}, nil, nil)
if !errors.Is(err, ErrInvalidConfig) {
t.Fatalf("err = %v, want ErrInvalidConfig", err)
}
}
func TestAdapter_Config_ReturnsSnapshot(t *testing.T) {
t.Parallel()
ad, err := New(Config{BaseURL: "https://ilinkai.weixin.qq.com", BotID: "bot-1"}, nil, nil)
if err != nil {
t.Fatalf("New: %v", err)
}
cfg := ad.Config()
if cfg["bot_id"] != "bot-1" {
t.Fatalf("Config()[bot_id] = %v, want bot-1", cfg["bot_id"])
}
if cfg["base_url"] != "https://ilinkai.weixin.qq.com" {
t.Fatalf("Config()[base_url] = %v", cfg["base_url"])
}
// 经 DecodeConfig 往返必须保留类型化配置。
var back Config
if err := adapter.DecodeConfig(cfg, &back); err != nil {
t.Fatalf("DecodeConfig: %v", err)
}
if back.BaseURL != "https://ilinkai.weixin.qq.com" || back.BotID != "bot-1" {
t.Fatalf("decoded config = %+v, want base_url/bot_id preserved", back)
}
}
func TestAdapter_Connect_WithToken_IsIdempotent(t *testing.T) {
t.Parallel()
ad, err := New(Config{BaseURL: "https://ilinkai.weixin.qq.com", BotToken: "tok-1"}, nil, nil)
if err != nil {
t.Fatalf("New: %v", err)
}
if ad.IsConnected() {
t.Fatal("IsConnected() = true before Connect")
}
if err := ad.Connect(context.Background()); err != nil {
t.Fatalf("Connect: %v", err)
}
if !ad.IsConnected() {
t.Fatal("IsConnected() = false after Connect")
}
// 第二次调用是无副作用的成功。
if err := ad.Connect(context.Background()); err != nil {
t.Fatalf("second Connect: %v", err)
}
}
func TestAdapter_HealthCheck(t *testing.T) {
t.Parallel()
t.Run("disconnected", func(t *testing.T) {
t.Parallel()
ad, _ := New(Config{BaseURL: "https://ilinkai.weixin.qq.com"}, nil, nil)
if err := ad.HealthCheck(context.Background()); !errors.Is(err, adapter.ErrNotConnected) {
t.Fatalf("HealthCheck = %v, want ErrNotConnected", err)
}
})
t.Run("connected_with_token", func(t *testing.T) {
t.Parallel()
ad, _ := New(Config{BaseURL: "https://ilinkai.weixin.qq.com", BotToken: "tok-1"}, nil, nil)
if err := ad.Connect(context.Background()); err != nil {
t.Fatalf("Connect: %v", err)
}
if err := ad.HealthCheck(context.Background()); err != nil {
t.Fatalf("HealthCheck = %v, want nil", err)
}
})
}
func TestAdapter_Disconnect_IsIdempotent(t *testing.T) {
t.Parallel()
ad, _ := New(Config{BaseURL: "https://ilinkai.weixin.qq.com", BotToken: "tok-1"}, nil, nil)
_ = ad.Connect(context.Background())
if err := ad.Disconnect(context.Background()); err != nil {
t.Fatalf("Disconnect: %v", err)
}
if ad.IsConnected() {
t.Fatal("IsConnected() = true after Disconnect")
}
if err := ad.Disconnect(context.Background()); err != nil {
t.Fatalf("second Disconnect: %v", err)
}
}
func TestAdapter_ListChannels(t *testing.T) {
t.Parallel()
ad, _ := New(Config{BaseURL: "https://ilinkai.weixin.qq.com", BotID: "bot-9"}, nil, nil)
chans, err := ad.ListChannels(context.Background())
if err != nil {
t.Fatalf("ListChannels: %v", err)
}
if len(chans) != 1 {
t.Fatalf("ListChannels() = %d channels, want 1", len(chans))
}
if chans[0].ChannelID != "bot-9" || chans[0].ChannelType != adapter.ChannelDirect {
t.Fatalf("channel = %+v, want {bot-9 direct}", chans[0])
}
}
func TestAdapter_SetMessageHandler_And_RecordInbound(t *testing.T) {
t.Parallel()
ad, _ := New(Config{BaseURL: "https://ilinkai.weixin.qq.com"}, nil, nil)
called := false
ad.SetMessageHandler(func(ctx context.Context, m adapter.UnifiedMessage) { called = true })
if ad.handlerLocked() == nil {
t.Fatal("handlerLocked() = nil after SetMessageHandler")
}
ad.SetMessageHandler(nil)
if ad.handlerLocked() != nil {
t.Fatal("handlerLocked() != nil after clearing")
}
if called {
t.Fatal("handler called before any message")
}
// recordInbound 必须刷新按对端的 token 与最后消息时间。
ad.recordInbound("tok-abc", adapter.UnifiedMessage{
SenderID: "user-1",
Timestamp: ad.clock(),
})
if got := ad.contextFor("user-1"); got != "tok-abc" {
t.Fatalf("contextFor(user-1) = %q, want tok-abc", got)
}
}
func TestBuildClientVersion(t *testing.T) {
t.Parallel()
cases := map[string]string{
"2.4.8": "132104", // 官方 @tencent-weixin/openclaw-weixin 2.4.8
"1.0.11": "65547", // 官方注释示例 0x0001000B
"1.2.3": "66051",
"0.0.0": "0",
"bad": "0",
}
for in, want := range cases {
if got := buildClientVersion(in); got != want {
t.Fatalf("buildClientVersion(%q) = %q, want %q", in, got, want)
}
}
}
func TestAdapter_Recipient_ResolvesGroupAndSender(t *testing.T) {
t.Parallel()
tests := []struct {
name string
msg adapter.UnifiedMessage
wantPeer string
wantGroup bool
}{
{name: "direct sender", msg: adapter.UnifiedMessage{SenderID: "u1"}, wantPeer: "u1"},
{name: "group id", msg: adapter.UnifiedMessage{ChannelType: adapter.ChannelGroup, GroupID: "g1"}, wantPeer: "g1", wantGroup: true},
{name: "default channel id", msg: adapter.UnifiedMessage{ChannelID: "c1"}, wantPeer: "c1"},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
peer, group := recipient(tc.msg)
if peer != tc.wantPeer || group != tc.wantGroup {
t.Fatalf("recipient() = (%q,%v), want (%q,%v)", peer, group, tc.wantPeer, tc.wantGroup)
}
})
}
}