1package imap_test
2
3import (
4	"bytes"
5	"reflect"
6	"testing"
7
8	"github.com/emersion/go-imap"
9)
10
11func TestResp_WriteTo(t *testing.T) {
12	var b bytes.Buffer
13	w := imap.NewWriter(&b)
14
15	resp := imap.NewUntaggedResp([]interface{}{imap.RawString("76"), imap.RawString("FETCH"), []interface{}{imap.RawString("UID"), 783}})
16	if err := resp.WriteTo(w); err != nil {
17		t.Fatal(err)
18	}
19
20	if b.String() != "* 76 FETCH (UID 783)\r\n" {
21		t.Error("Invalid response:", b.String())
22	}
23}
24
25func TestContinuationReq_WriteTo(t *testing.T) {
26	var b bytes.Buffer
27	w := imap.NewWriter(&b)
28
29	resp := &imap.ContinuationReq{}
30
31	if err := resp.WriteTo(w); err != nil {
32		t.Fatal(err)
33	}
34
35	if b.String() != "+\r\n" {
36		t.Error("Invalid continuation:", b.String())
37	}
38}
39
40func TestContinuationReq_WriteTo_WithInfo(t *testing.T) {
41	var b bytes.Buffer
42	w := imap.NewWriter(&b)
43
44	resp := &imap.ContinuationReq{Info: "send literal"}
45
46	if err := resp.WriteTo(w); err != nil {
47		t.Fatal(err)
48	}
49
50	if b.String() != "+ send literal\r\n" {
51		t.Error("Invalid continuation:", b.String())
52	}
53}
54
55func TestReadResp_ContinuationReq(t *testing.T) {
56	b := bytes.NewBufferString("+ send literal\r\n")
57	r := imap.NewReader(b)
58
59	resp, err := imap.ReadResp(r)
60	if err != nil {
61		t.Fatal(err)
62	}
63
64	cont, ok := resp.(*imap.ContinuationReq)
65	if !ok {
66		t.Fatal("Response is not a continuation request")
67	}
68
69	if cont.Info != "send literal" {
70		t.Error("Invalid info:", cont.Info)
71	}
72}
73
74func TestReadResp_ContinuationReq_NoInfo(t *testing.T) {
75	b := bytes.NewBufferString("+\r\n")
76	r := imap.NewReader(b)
77
78	resp, err := imap.ReadResp(r)
79	if err != nil {
80		t.Fatal(err)
81	}
82
83	cont, ok := resp.(*imap.ContinuationReq)
84	if !ok {
85		t.Fatal("Response is not a continuation request")
86	}
87
88	if cont.Info != "" {
89		t.Error("Invalid info:", cont.Info)
90	}
91}
92
93func TestReadResp_Resp(t *testing.T) {
94	b := bytes.NewBufferString("* 1 EXISTS\r\n")
95	r := imap.NewReader(b)
96
97	resp, err := imap.ReadResp(r)
98	if err != nil {
99		t.Fatal(err)
100	}
101
102	data, ok := resp.(*imap.DataResp)
103	if !ok {
104		t.Fatal("Invalid response type")
105	}
106
107	if data.Tag != "*" {
108		t.Error("Invalid tag:", data.Tag)
109	}
110	if len(data.Fields) != 2 {
111		t.Error("Invalid fields:", data.Fields)
112	}
113}
114
115func TestReadResp_Resp_NoArgs(t *testing.T) {
116	b := bytes.NewBufferString("* SEARCH\r\n")
117	r := imap.NewReader(b)
118
119	resp, err := imap.ReadResp(r)
120	if err != nil {
121		t.Fatal(err)
122	}
123
124	data, ok := resp.(*imap.DataResp)
125	if !ok {
126		t.Fatal("Invalid response type")
127	}
128
129	if data.Tag != "*" {
130		t.Error("Invalid tag:", data.Tag)
131	}
132	if len(data.Fields) != 1 || data.Fields[0] != "SEARCH" {
133		t.Error("Invalid fields:", data.Fields)
134	}
135}
136
137func TestReadResp_StatusResp(t *testing.T) {
138	tests := []struct {
139		input    string
140		expected *imap.StatusResp
141	}{
142		{
143			input: "* OK IMAP4rev1 Service Ready\r\n",
144			expected: &imap.StatusResp{
145				Tag:  "*",
146				Type: imap.StatusRespOk,
147				Info: "IMAP4rev1 Service Ready",
148			},
149		},
150		{
151			input: "* PREAUTH Welcome Pauline!\r\n",
152			expected: &imap.StatusResp{
153				Tag:  "*",
154				Type: imap.StatusRespPreauth,
155				Info: "Welcome Pauline!",
156			},
157		},
158		{
159			input: "a001 OK NOOP completed\r\n",
160			expected: &imap.StatusResp{
161				Tag:  "a001",
162				Type: imap.StatusRespOk,
163				Info: "NOOP completed",
164			},
165		},
166		{
167			input: "a001 OK [READ-ONLY] SELECT completed\r\n",
168			expected: &imap.StatusResp{
169				Tag:  "a001",
170				Type: imap.StatusRespOk,
171				Code: "READ-ONLY",
172				Info: "SELECT completed",
173			},
174		},
175		{
176			input: "a001 OK [CAPABILITY IMAP4rev1 UIDPLUS] LOGIN completed\r\n",
177			expected: &imap.StatusResp{
178				Tag:       "a001",
179				Type:      imap.StatusRespOk,
180				Code:      "CAPABILITY",
181				Arguments: []interface{}{"IMAP4rev1", "UIDPLUS"},
182				Info:      "LOGIN completed",
183			},
184		},
185	}
186
187	for _, test := range tests {
188		b := bytes.NewBufferString(test.input)
189		r := imap.NewReader(b)
190
191		resp, err := imap.ReadResp(r)
192		if err != nil {
193			t.Fatal(err)
194		}
195
196		status, ok := resp.(*imap.StatusResp)
197		if !ok {
198			t.Fatal("Response is not a status:", resp)
199		}
200
201		if status.Tag != test.expected.Tag {
202			t.Errorf("Invalid tag: expected %v but got %v", status.Tag, test.expected.Tag)
203		}
204		if status.Type != test.expected.Type {
205			t.Errorf("Invalid type: expected %v but got %v", status.Type, test.expected.Type)
206		}
207		if status.Code != test.expected.Code {
208			t.Errorf("Invalid code: expected %v but got %v", status.Code, test.expected.Code)
209		}
210		if len(status.Arguments) != len(test.expected.Arguments) {
211			t.Errorf("Invalid arguments: expected %v but got %v", status.Arguments, test.expected.Arguments)
212		}
213		if status.Info != test.expected.Info {
214			t.Errorf("Invalid info: expected %v but got %v", status.Info, test.expected.Info)
215		}
216	}
217}
218
219func TestParseNamedResp(t *testing.T) {
220	tests := []struct {
221		resp   *imap.DataResp
222		name   string
223		fields []interface{}
224	}{
225		{
226			resp:   &imap.DataResp{Fields: []interface{}{"CAPABILITY", "IMAP4rev1"}},
227			name:   "CAPABILITY",
228			fields: []interface{}{"IMAP4rev1"},
229		},
230		{
231			resp:   &imap.DataResp{Fields: []interface{}{"42", "EXISTS"}},
232			name:   "EXISTS",
233			fields: []interface{}{"42"},
234		},
235		{
236			resp:   &imap.DataResp{Fields: []interface{}{"42", "FETCH", "blah"}},
237			name:   "FETCH",
238			fields: []interface{}{"42", "blah"},
239		},
240	}
241
242	for _, test := range tests {
243		name, fields, ok := imap.ParseNamedResp(test.resp)
244		if !ok {
245			t.Errorf("ParseNamedResp(%v)[2] = false, want true", test.resp)
246		} else if name != test.name {
247			t.Errorf("ParseNamedResp(%v)[0] = %v, want %v", test.resp, name, test.name)
248		} else if !reflect.DeepEqual(fields, test.fields) {
249			t.Errorf("ParseNamedResp(%v)[1] = %v, want %v", test.resp, fields, test.fields)
250		}
251	}
252}
253