mox/imapserver/list_test.go
Mechiel Lukkien cb229cb6cf
mox!
2023-01-30 14:27:06 +01:00

215 lines
6.7 KiB
Go

package imapserver
import (
"testing"
"github.com/mjl-/mox/imapclient"
"github.com/mjl-/mox/store"
)
func TestListBasic(t *testing.T) {
tc := start(t)
defer tc.close()
tc.client.Login("mjl@mox.example", "testtest")
ulist := func(name string, flags ...string) imapclient.UntaggedList {
if len(flags) == 0 {
flags = nil
}
return imapclient.UntaggedList{Flags: flags, Separator: '/', Mailbox: name}
}
tc.last(tc.client.List("INBOX"))
tc.xuntagged(ulist("Inbox"))
tc.last(tc.client.List("Inbox"))
tc.xuntagged(ulist("Inbox"))
tc.last(tc.client.List("%"))
tc.xuntagged(ulist("Archive"), ulist("Drafts"), ulist("Inbox"), ulist("Junk"), ulist("Sent"), ulist("Trash"))
tc.last(tc.client.List("*"))
tc.xuntagged(ulist("Archive"), ulist("Drafts"), ulist("Inbox"), ulist("Junk"), ulist("Sent"), ulist("Trash"))
tc.last(tc.client.List("A*"))
tc.xuntagged(ulist("Archive"))
tc.client.Create("Inbox/todo")
tc.last(tc.client.List("Inbox*"))
tc.xuntagged(ulist("Inbox"), ulist("Inbox/todo"))
tc.last(tc.client.List("Inbox/%"))
tc.xuntagged(ulist("Inbox/todo"))
tc.last(tc.client.List("Inbox/*"))
tc.xuntagged(ulist("Inbox/todo"))
// Leading full INBOX is turned into Inbox, so mailbox matches.
tc.last(tc.client.List("INBOX/*"))
tc.xuntagged(ulist("Inbox/todo"))
// No match because we are only touching various casings of the full "INBOX".
tc.last(tc.client.List("INBO*"))
tc.xuntagged()
}
func TestListExtended(t *testing.T) {
defer mockUIDValidity()()
tc := start(t)
defer tc.close()
tc.client.Login("mjl@mox.example", "testtest")
ulist := func(name string, flags ...string) imapclient.UntaggedList {
if len(flags) == 0 {
flags = nil
}
return imapclient.UntaggedList{Flags: flags, Separator: '/', Mailbox: name}
}
uidvals := map[string]uint32{}
for _, name := range store.InitialMailboxes {
uidvals[name] = 1
}
var uidvalnext uint32 = 2
uidval := func(name string) uint32 {
v, ok := uidvals[name]
if !ok {
v = uidvalnext
uidvals[name] = v
uidvalnext++
}
return v
}
ustatus := func(name string) imapclient.UntaggedStatus {
attrs := map[string]int64{
"MESSAGES": 0,
"UIDNEXT": 1,
"UIDVALIDITY": int64(uidval(name)),
"UNSEEN": 0,
"DELETED": 0,
"SIZE": 0,
"RECENT": 0,
"APPENDLIMIT": 0,
}
return imapclient.UntaggedStatus{Mailbox: name, Attrs: attrs}
}
const (
Fsubscribed = `\Subscribed`
Fhaschildren = `\HasChildren`
Fhasnochildren = `\HasNoChildren`
Fnonexistent = `\NonExistent`
Farchive = `\Archive`
Fdraft = `\Draft`
Fjunk = `\Junk`
Fsent = `\Sent`
Ftrash = `\Trash`
)
// untaggedlist with flags subscribed and hasnochildren
xlist := func(name string, flags ...string) imapclient.UntaggedList {
flags = append([]string{Fhasnochildren, Fsubscribed}, flags...)
return ulist(name, flags...)
}
xchildlist := func(name string, flags ...string) imapclient.UntaggedList {
u := ulist(name, flags...)
comp := imapclient.TaggedExtComp{String: "SUBSCRIBED"}
u.Extended = []imapclient.MboxListExtendedItem{{Tag: "CHILDINFO", Val: imapclient.TaggedExtVal{Comp: &comp}}}
return u
}
tc.last(tc.client.ListFull(false, "INBOX"))
tc.xuntagged(xlist("Inbox"), ustatus("Inbox"))
tc.last(tc.client.ListFull(false, "Inbox"))
tc.xuntagged(xlist("Inbox"), ustatus("Inbox"))
tc.last(tc.client.ListFull(false, "%"))
tc.xuntagged(xlist("Archive", Farchive), ustatus("Archive"), xlist("Drafts", Fdraft), ustatus("Drafts"), xlist("Inbox"), ustatus("Inbox"), xlist("Junk", Fjunk), ustatus("Junk"), xlist("Sent", Fsent), ustatus("Sent"), xlist("Trash", Ftrash), ustatus("Trash"))
tc.last(tc.client.ListFull(false, "*"))
tc.xuntagged(xlist("Archive", Farchive), ustatus("Archive"), xlist("Drafts", Fdraft), ustatus("Drafts"), xlist("Inbox"), ustatus("Inbox"), xlist("Junk", Fjunk), ustatus("Junk"), xlist("Sent", Fsent), ustatus("Sent"), xlist("Trash", Ftrash), ustatus("Trash"))
tc.last(tc.client.ListFull(false, "A*"))
tc.xuntagged(xlist("Archive", Farchive), ustatus("Archive"))
tc.last(tc.client.ListFull(false, "A*", "Junk"))
tc.xuntagged(xlist("Archive", Farchive), ustatus("Archive"), xlist("Junk", Fjunk), ustatus("Junk"))
tc.client.Create("Inbox/todo")
tc.last(tc.client.ListFull(false, "Inbox*"))
tc.xuntagged(ulist("Inbox", Fhaschildren, Fsubscribed), ustatus("Inbox"), xlist("Inbox/todo"), ustatus("Inbox/todo"))
tc.last(tc.client.ListFull(false, "Inbox/%"))
tc.xuntagged(xlist("Inbox/todo"), ustatus("Inbox/todo"))
tc.last(tc.client.ListFull(false, "Inbox/*"))
tc.xuntagged(xlist("Inbox/todo"), ustatus("Inbox/todo"))
// Leading full INBOX is turned into Inbox, so mailbox matches.
tc.last(tc.client.ListFull(false, "INBOX/*"))
tc.xuntagged(xlist("Inbox/todo"), ustatus("Inbox/todo"))
// No match because we are only touching various casings of the full "INBOX".
tc.last(tc.client.ListFull(false, "INBO*"))
tc.xuntagged()
tc.last(tc.client.ListFull(true, "Inbox"))
tc.xuntagged(xchildlist("Inbox", Fsubscribed, Fhaschildren), ustatus("Inbox"))
tc.client.Unsubscribe("Inbox")
tc.last(tc.client.ListFull(true, "Inbox"))
tc.xuntagged(xchildlist("Inbox", Fhaschildren), ustatus("Inbox"))
tc.client.Delete("Inbox/todo") // Still subscribed.
tc.last(tc.client.ListFull(true, "Inbox"))
tc.xuntagged(xchildlist("Inbox", Fhasnochildren), ustatus("Inbox"))
// Simple extended list without RETURN options.
tc.transactf("ok", `list "" ("inbox")`)
tc.xuntagged(ulist("Inbox"))
tc.transactf("ok", `list () "" ("inbox") return ()`)
tc.xuntagged(ulist("Inbox"))
tc.transactf("ok", `list "" ("inbox") return ()`)
tc.xuntagged(ulist("Inbox"))
tc.transactf("ok", `list () "" ("inbox")`)
tc.xuntagged(ulist("Inbox"))
tc.transactf("ok", `list (remote) "" ("inbox")`)
tc.xuntagged(ulist("Inbox"))
tc.transactf("ok", `list (remote) "" "/inbox"`)
tc.xuntagged()
tc.transactf("ok", `list (remote) "/inbox" ""`)
tc.xuntagged()
tc.transactf("ok", `list (remote) "inbox" ""`)
tc.xuntagged()
tc.transactf("ok", `list (remote) "inbox" "a"`)
tc.xuntagged()
tc.client.Create("inbox/a")
tc.transactf("ok", `list (remote) "inbox" "a"`)
tc.xuntagged(ulist("Inbox/a"))
tc.client.Subscribe("x")
tc.transactf("ok", `list (subscribed) "" x return (subscribed)`)
tc.xuntagged(imapclient.UntaggedList{Flags: []string{`\Subscribed`, `\NonExistent`}, Separator: '/', Mailbox: "x"})
tc.transactf("bad", `list (recursivematch) "" "*"`) // Cannot have recursivematch without a base selection option like subscribed.
tc.transactf("bad", `list (recursivematch remote) "" "*"`) // "remote" is not a base selection option.
tc.transactf("bad", `list (unknown) "" "*"`) // Unknown selection options must result in BAD.
tc.transactf("bad", `list () "" "*" return (unknown)`) // Unknown return options must result in BAD.
}