| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- package webapi
- import (
- "net/http"
- "net/http/httptest"
- "testing"
- "github.com/stretchr/testify/assert"
- )
- // Some clients read these response keys strictly, throwing on an absent key rather
- // than treating it as empty, and nothing surfaces that failure: an event parse is
- // dropped and a queued request retried forever. Each key below must therefore be
- // present even when its value is empty, zero or false — presence is the contract, not
- // the value. These tests keep a future `omitempty` from reintroducing the failure.
- // renderJSON sends payload through the default JSON path and returns the body.
- func renderJSON(t *testing.T, data any) string {
- t.Helper()
- rr := httptest.NewRecorder()
- SendOK(rr, httptest.NewRequest(http.MethodGet, "/x?f=json", nil), data, nil)
- return rr.Body.String()
- }
- func TestStrictKeys_IMEvents(t *testing.T) {
- t.Run("im carries imf and autoresponse when false", func(t *testing.T) {
- body := renderJSON(t, IMEvent{
- Source: UserInfo{AimID: "chattingchuck"},
- Message: "hi",
- Imf: imfPlainText,
- })
- assert.Contains(t, body, `"imf":"plain"`)
- assert.Contains(t, body, `"autoresponse":false`)
- })
- t.Run("offlineIM carries imf and autoresponse when false", func(t *testing.T) {
- body := renderJSON(t, OfflineIMEvent{
- AimID: "chattingchuck",
- Message: "hi",
- Imf: imfPlainText,
- })
- assert.Contains(t, body, `"imf":"plain"`)
- assert.Contains(t, body, `"autoresponse":false`)
- })
- }
- func TestStrictKeys_BuddyGroupID(t *testing.T) {
- // The zero id is the interesting case: omitempty here would drop the key for
- // the group the client is most likely to have, and cost it the whole roster.
- body := renderJSON(t, BuddyListData{Groups: []BuddyGroup{{
- Name: "Buddies", ID: 0, Buddies: []BuddyInfo{},
- }}})
- assert.Contains(t, body, `"id":0`)
- }
- func TestStrictKeys_PresenceUsers(t *testing.T) {
- // Each query fills in one field, and a match of none must still render that
- // field as an empty array rather than drop it: a client reading data.users or
- // data.groups strictly cannot tell an absent key from a failed request.
- populatedGroups := []BuddyGroupInfo{{Name: "Buddies", Buddies: []BuddyPresenceInfo{}}}
- t.Run("empty user result still renders the array", func(t *testing.T) {
- body := renderJSON(t, PresenceData{Users: []BuddyPresenceInfo{}})
- assert.Contains(t, body, `"users":[]`)
- })
- t.Run("empty group result still renders the array", func(t *testing.T) {
- body := renderJSON(t, PresenceData{Groups: []BuddyGroupInfo{}})
- assert.Contains(t, body, `"groups":[]`)
- })
- t.Run("buddy list query omits users", func(t *testing.T) {
- body := renderJSON(t, PresenceData{Groups: populatedGroups})
- assert.NotContains(t, body, `"users"`)
- })
- t.Run("presence query omits groups", func(t *testing.T) {
- body := renderJSON(t, PresenceData{Users: []BuddyPresenceInfo{}})
- assert.NotContains(t, body, `"groups"`)
- })
- }
- func TestStrictKeys_FetchEventsArray(t *testing.T) {
- // A nil slice renders as null, which throws exactly as an absent key does — and
- // a poll that throws is retried every 5s forever.
- body := renderJSON(t, &FetchEventsData{Events: []Event{}})
- assert.Contains(t, body, `"events":[]`)
- assert.NotContains(t, body, `"events":null`)
- }
- func TestStrictKeys_GetInfoUserData(t *testing.T) {
- // The web client reads loginId and displayName off userData unconditionally, so
- // both keys must survive a blank name.
- body := renderJSON(t, GetInfoData{})
- assert.Contains(t, body, `"loginId":""`)
- assert.Contains(t, body, `"displayName":""`)
- }
|