package payment import ( "context" "net/http" "testing" ) // stubChannel 是测试用的假渠道,验证 Manager 注册表逻辑(不打真渠道网络)。 type stubChannel struct{ name string } func (s stubChannel) Name() string { return s.name } func (s stubChannel) CreatePay(_ context.Context, _, _ string, _ int64) (PayIntent, error) { return PayIntent{CodeURL: "stub://" + s.name}, nil } func (s stubChannel) QueryOrder(_ context.Context, _ string) (PayResult, error) { return PayResult{}, nil } func (s stubChannel) VerifyCallback(_ *http.Request) (PayResult, error) { return PayResult{}, nil } // 空 Manager:Get 任意渠道为 nil,Available 为空,Status 报未配置。 func TestManager_EmptyRegistry(t *testing.T) { m := NewManager() if m.Get(ChannelWechat) != nil { t.Error("未注册渠道 Get 应为 nil") } if len(m.Available()) != 0 { t.Errorf("空注册表 Available 应为空,得 %v", m.Available()) } if ok, reason := m.Status(ChannelWechat); ok || reason == "" { t.Errorf("空注册表 wechat 应未启用且有原因,得 ok=%v reason=%q", ok, reason) } } // register 生效:注册后 Get 取到、Available 含之、Status 启用;置 nil 则摘除并留原因。 func TestManager_RegisterAndRemove(t *testing.T) { m := NewManager() m.register(ChannelWechat, stubChannel{name: ChannelWechat}, "") if got := m.Get(ChannelWechat); got == nil || got.Name() != ChannelWechat { t.Fatalf("注册后应能 Get 到 wechat,得 %v", got) } if ok, _ := m.Status(ChannelWechat); !ok { t.Error("注册后 Status 应启用") } avail := m.Available() if len(avail) != 1 || avail[0] != ChannelWechat { t.Errorf("Available 应含 wechat,得 %v", avail) } // 再注册第二个渠道 → Available 有序返回两个。 m.register(ChannelAlipay, stubChannel{name: ChannelAlipay}, "") if avail := m.Available(); len(avail) != 2 || avail[0] != ChannelAlipay || avail[1] != ChannelWechat { t.Errorf("Available 应有序含 alipay,wechat,得 %v", avail) } // 置 nil(配置变坏/清空)→ 摘除,Get 为 nil、Status 未启用且保留原因。 m.register(ChannelWechat, nil, "配置不全,缺: mchid") if m.Get(ChannelWechat) != nil { t.Error("摘除后 Get 应为 nil") } if ok, reason := m.Status(ChannelWechat); ok || reason != "配置不全,缺: mchid" { t.Errorf("摘除后应未启用且保留原因,得 ok=%v reason=%q", ok, reason) } } // ReloadWechat 空配置:不算错、渠道保持隐藏、原因为「未配置」。 func TestManager_ReloadWechat_Empty(t *testing.T) { m := NewManager() if err := m.ReloadWechat(context.Background(), Config{}); err != nil { t.Errorf("空配置 ReloadWechat 不应报错,得 %v", err) } if m.Get(ChannelWechat) != nil { t.Error("空配置不应启用渠道") } if ok, reason := m.Status(ChannelWechat); ok || reason != "未配置" { t.Errorf("空配置应报未配置,得 ok=%v reason=%q", ok, reason) } } // ReloadWechat 配置不全:返回错误、渠道隐藏、原因列出缺失字段。 func TestManager_ReloadWechat_Incomplete(t *testing.T) { m := NewManager() err := m.ReloadWechat(context.Background(), Config{MchID: "123"}) // 只填一个字段 if err == nil { t.Error("配置不全应返回错误") } if m.Get(ChannelWechat) != nil { t.Error("配置不全不应启用渠道") } if _, reason := m.Status(ChannelWechat); reason == "" { t.Error("配置不全应给出缺失原因") } }