package imapx import ( "testing" "github.com/emersion/go-imap/v2" ) // metaBatches must tile the sequence 1..total into contiguous, non-overlapping // windows of at most batchSize, covering every message exactly once. A single // unbounded FETCH 1:* is what wedges large mailboxes; batching keeps each // command short so the server stays responsive and ctx can be checked between // windows. func TestMetaBatches(t *testing.T) { cases := []struct { total, size uint32 want []imap.SeqRange }{ {0, 1000, nil}, {1, 1000, []imap.SeqRange{{Start: 1, Stop: 1}}}, {1000, 1000, []imap.SeqRange{{Start: 1, Stop: 1000}}}, {1001, 1000, []imap.SeqRange{{Start: 1, Stop: 1000}, {Start: 1001, Stop: 1001}}}, {2500, 1000, []imap.SeqRange{{Start: 1, Stop: 1000}, {Start: 1001, Stop: 2000}, {Start: 2001, Stop: 2500}}}, } for _, c := range cases { got := metaBatches(c.total, c.size) if len(got) != len(c.want) { t.Fatalf("total=%d size=%d: got %d windows %v, want %d %v", c.total, c.size, len(got), got, len(c.want), c.want) } for i := range got { if got[i] != c.want[i] { t.Fatalf("total=%d size=%d window %d: got %+v want %+v", c.total, c.size, i, got[i], c.want[i]) } } } } // Every window must be within 1..total and the windows must be gap-free so no // message is skipped or fetched twice. func TestMetaBatchesCoverage(t *testing.T) { const total, size = 4321, 1000 got := metaBatches(total, size) if got[0].Start != 1 { t.Fatalf("first window must start at 1, got %d", got[0].Start) } if last := got[len(got)-1]; last.Stop != total { t.Fatalf("last window must stop at total=%d, got %d", total, last.Stop) } for i := 1; i < len(got); i++ { if got[i].Start != got[i-1].Stop+1 { t.Fatalf("gap/overlap between window %d (%+v) and %d (%+v)", i-1, got[i-1], i, got[i]) } } }