1package imap_test
2
3import (
4	"fmt"
5	"reflect"
6	"sort"
7	"testing"
8
9	"github.com/emersion/go-imap"
10	"github.com/emersion/go-imap/internal"
11)
12
13func TestCanonicalMailboxName(t *testing.T) {
14	if got := imap.CanonicalMailboxName("Inbox"); got != imap.InboxName {
15		t.Errorf("Invalid canonical mailbox name: expected %q but got %q", imap.InboxName, got)
16	}
17	if got := imap.CanonicalMailboxName("Drafts"); got != "Drafts" {
18		t.Errorf("Invalid canonical mailbox name: expected %q but got %q", "Drafts", got)
19	}
20}
21
22var mailboxInfoTests = []struct {
23	fields []interface{}
24	info   *imap.MailboxInfo
25}{
26	{
27		fields: []interface{}{
28			[]interface{}{"\\Noselect", "\\Recent", "\\Unseen"},
29			"/",
30			"INBOX",
31		},
32		info: &imap.MailboxInfo{
33			Attributes: []string{"\\Noselect", "\\Recent", "\\Unseen"},
34			Delimiter:  "/",
35			Name:       "INBOX",
36		},
37	},
38}
39
40func TestMailboxInfo_Parse(t *testing.T) {
41	for _, test := range mailboxInfoTests {
42		info := &imap.MailboxInfo{}
43		if err := info.Parse(test.fields); err != nil {
44			t.Fatal(err)
45		}
46
47		if fmt.Sprint(info.Attributes) != fmt.Sprint(test.info.Attributes) {
48			t.Fatal("Invalid flags:", info.Attributes)
49		}
50		if info.Delimiter != test.info.Delimiter {
51			t.Fatal("Invalid delimiter:", info.Delimiter)
52		}
53		if info.Name != test.info.Name {
54			t.Fatal("Invalid name:", info.Name)
55		}
56	}
57}
58
59func TestMailboxInfo_Format(t *testing.T) {
60	for _, test := range mailboxInfoTests {
61		fields := test.info.Format()
62
63		if fmt.Sprint(fields) != fmt.Sprint(test.fields) {
64			t.Fatal("Invalid fields:", fields)
65		}
66	}
67}
68
69var mailboxInfoMatchTests = []struct {
70	name, ref, pattern string
71	result             bool
72}{
73	{name: "INBOX", pattern: "INBOX", result: true},
74	{name: "INBOX", pattern: "Asuka", result: false},
75	{name: "INBOX", pattern: "*", result: true},
76	{name: "INBOX", pattern: "%", result: true},
77	{name: "Neon Genesis Evangelion/Misato", pattern: "*", result: true},
78	{name: "Neon Genesis Evangelion/Misato", pattern: "%", result: false},
79	{name: "Neon Genesis Evangelion/Misato", pattern: "Neon Genesis Evangelion/*", result: true},
80	{name: "Neon Genesis Evangelion/Misato", pattern: "Neon Genesis Evangelion/%", result: true},
81	{name: "Neon Genesis Evangelion/Misato", pattern: "Neo* Evangelion/Misato", result: true},
82	{name: "Neon Genesis Evangelion/Misato", pattern: "Neo% Evangelion/Misato", result: true},
83	{name: "Neon Genesis Evangelion/Misato", pattern: "*Eva*/Misato", result: true},
84	{name: "Neon Genesis Evangelion/Misato", pattern: "%Eva%/Misato", result: true},
85	{name: "Neon Genesis Evangelion/Misato", pattern: "*X*/Misato", result: false},
86	{name: "Neon Genesis Evangelion/Misato", pattern: "%X%/Misato", result: false},
87	{name: "Neon Genesis Evangelion/Misato", pattern: "Neon Genesis Evangelion/Mi%o", result: true},
88	{name: "Neon Genesis Evangelion/Misato", pattern: "Neon Genesis Evangelion/Mi%too", result: false},
89	{name: "Misato/Misato", pattern: "Mis*to/Misato", result: true},
90	{name: "Misato/Misato", pattern: "Mis*to", result: true},
91	{name: "Misato/Misato/Misato", pattern: "Mis*to/Mis%to", result: true},
92	{name: "Misato/Misato", pattern: "Mis**to/Misato", result: true},
93	{name: "Misato/Misato", pattern: "Misat%/Misato", result: true},
94	{name: "Misato/Misato", pattern: "Misat%Misato", result: false},
95	{name: "Misato/Misato", ref: "Misato", pattern: "Misato", result: true},
96	{name: "Misato/Misato", ref: "Misato/", pattern: "Misato", result: true},
97	{name: "Misato/Misato", ref: "Shinji", pattern: "/Misato/*", result: true},
98	{name: "Misato/Misato", ref: "Misato", pattern: "/Misato", result: false},
99	{name: "Misato/Misato", ref: "Misato", pattern: "Shinji", result: false},
100	{name: "Misato/Misato", ref: "Shinji", pattern: "Misato", result: false},
101}
102
103func TestMailboxInfo_Match(t *testing.T) {
104	for _, test := range mailboxInfoMatchTests {
105		info := &imap.MailboxInfo{Name: test.name, Delimiter: "/"}
106		result := info.Match(test.ref, test.pattern)
107		if result != test.result {
108			t.Errorf("Matching name %q with pattern %q and reference %q returns %v, but expected %v", test.name, test.pattern, test.ref, result, test.result)
109		}
110	}
111}
112
113func TestNewMailboxStatus(t *testing.T) {
114	status := imap.NewMailboxStatus("INBOX", []imap.StatusItem{imap.StatusMessages, imap.StatusUnseen})
115
116	expected := &imap.MailboxStatus{
117		Name:  "INBOX",
118		Items: map[imap.StatusItem]interface{}{imap.StatusMessages: nil, imap.StatusUnseen: nil},
119	}
120
121	if !reflect.DeepEqual(expected, status) {
122		t.Errorf("Invalid mailbox status: expected \n%+v\n but got \n%+v", expected, status)
123	}
124}
125
126var mailboxStatusTests = [...]struct {
127	fields []interface{}
128	status *imap.MailboxStatus
129}{
130	{
131		fields: []interface{}{
132			"MESSAGES", uint32(42),
133			"RECENT", uint32(1),
134			"UNSEEN", uint32(6),
135			"UIDNEXT", uint32(65536),
136			"UIDVALIDITY", uint32(4242),
137		},
138		status: &imap.MailboxStatus{
139			Items: map[imap.StatusItem]interface{}{
140				imap.StatusMessages:    nil,
141				imap.StatusRecent:      nil,
142				imap.StatusUnseen:      nil,
143				imap.StatusUidNext:     nil,
144				imap.StatusUidValidity: nil,
145			},
146			Messages:    42,
147			Recent:      1,
148			Unseen:      6,
149			UidNext:     65536,
150			UidValidity: 4242,
151		},
152	},
153}
154
155func TestMailboxStatus_Parse(t *testing.T) {
156	for i, test := range mailboxStatusTests {
157		status := &imap.MailboxStatus{}
158		if err := status.Parse(test.fields); err != nil {
159			t.Errorf("Expected no error while parsing mailbox status #%v, got: %v", i, err)
160			continue
161		}
162
163		if !reflect.DeepEqual(status, test.status) {
164			t.Errorf("Invalid parsed mailbox status for #%v: got \n%+v\n but expected \n%+v", i, status, test.status)
165		}
166	}
167}
168
169func TestMailboxStatus_Format(t *testing.T) {
170	for i, test := range mailboxStatusTests {
171		fields := test.status.Format()
172
173		// MapListSorter does not know about RawString and will panic.
174		stringFields := make([]interface{}, 0, len(fields))
175		for _, field := range fields {
176			if s, ok := field.(imap.RawString); ok {
177				stringFields = append(stringFields, string(s))
178			} else {
179				stringFields = append(stringFields, field)
180			}
181		}
182
183		sort.Sort(internal.MapListSorter(stringFields))
184
185		sort.Sort(internal.MapListSorter(test.fields))
186
187		if !reflect.DeepEqual(stringFields, test.fields) {
188			t.Errorf("Invalid mailbox status fields for #%v: got \n%+v\n but expected \n%+v", i, fields, test.fields)
189		}
190	}
191}
192