package adapter import ( "encoding/json" "io" "net/http" "net/http/httptest" "strings" "testing" ) func TestGroupsFromUpdatesKeepsGroupsDropsPrivate(t *testing.T) { body := []byte(`{ "ok": true, "result": [ {"update_id": 100000001, "message": {"chat": {"id": 10000778141, "type": "group", "title": "测试AI"}}}, {"update_id": 100000002, "message": {"chat": {"id": 11, "type": "private", "first_name": "u"}}}, {"update_id": 100000003, "my_chat_member": {"chat": {"id": 22, "type": "supergroup", "title": "SG", "username": "sg_name"}}} ] }`) chats, maxID, err := GroupsFromUpdates(body) if err != nil { t.Fatal(err) } if maxID != 100000003 { t.Fatalf("maxID=%d", maxID) } if len(chats) != 2 { t.Fatalf("len=%d want 2: %#v", len(chats), chats) } byID := map[string]SafewChat{} for _, c := range chats { byID[c.ID] = c } g := byID["10000778141"] if g.Type != "group" || g.Title != "测试AI" { t.Fatalf("group: %#v", g) } raw, _ := json.Marshal(g) var m map[string]any _ = json.Unmarshal(raw, &m) if _, ok := m["id"].(string); !ok { t.Fatalf("id JSON type = %T, want string", m["id"]) } sg := byID["22"] if sg.Username == nil || *sg.Username != "sg_name" { t.Fatalf("username: %#v", sg) } } func TestFilterSafewChats(t *testing.T) { chats := []SafewChat{ {ID: "10000778141", Type: "group", Title: "测试AI"}, {ID: "99", Type: "group", Title: "ops"}, } got := FilterSafewChats(chats, "测试") if len(got) != 1 || got[0].ID != "10000778141" { t.Fatalf("%#v", got) } got = FilterSafewChats(chats, "10000778141") if len(got) != 1 || got[0].Title != "测试AI" { t.Fatalf("%#v", got) } got = FilterSafewChats(chats, "") if len(got) != 2 { t.Fatalf("empty q should keep all, got %d", len(got)) } } func TestPollGroupChatsSuccess(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/bottok/getUpdates" { t.Errorf("path=%s", r.URL.Path) } raw, _ := io.ReadAll(r.Body) var body map[string]any _ = json.Unmarshal(raw, &body) if body["timeout"] != float64(0) { t.Errorf("timeout=%v", body["timeout"]) } if body["offset"] != float64(5) { t.Errorf("offset=%v", body["offset"]) } w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(`{"ok":true,"result":[{"update_id":10,"message":{"chat":{"id":10000778141,"type":"group","title":"测试AI"}}}]}`)) })) defer srv.Close() s := &SafeWSender{apiBase: srv.URL} chats, next, err := s.PollGroupChats("tok", 5, 0) if err != nil { t.Fatal(err) } if next != 11 { t.Fatalf("next=%d want 11", next) } if len(chats) != 1 || chats[0].ID != "10000778141" { t.Fatalf("%#v", chats) } } func TestSafewErrorDescriptionIncludesErrorMsg(t *testing.T) { got := safewErrorDescription([]byte(`{"ok":false,"description":"BAD_REQUEST","error_msg":"Conflict: terminated by other getUpdates request"}`)) if !strings.Contains(got, "Conflict") { t.Fatalf("got %q, want error_msg", got) } } func TestPollGroupChatsUnauthorized(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusUnauthorized) _, _ = w.Write([]byte(`{"ok":false,"error_code":401,"description":"BOT_TOKEN_INVALID"}`)) })) defer srv.Close() s := &SafeWSender{apiBase: srv.URL} _, _, err := s.PollGroupChats("bad", 0, 0) if err == nil { t.Fatal("expected error") } ae, ok := err.(*SafewAuthError) if !ok { t.Fatalf("type %T %v", err, err) } if !strings.Contains(ae.Description, "BOT_TOKEN_INVALID") { t.Fatalf("%q", ae.Description) } }