1package xmpp
2
3import (
4	"encoding/base64"
5	"encoding/xml"
6	"errors"
7
8	"github.com/coyim/coyim/xmpp/data"
9
10	. "gopkg.in/check.v1"
11)
12
13type FormsXMPPSuite struct{}
14
15var _ = Suite(&FormsXMPPSuite{})
16
17func (s *FormsXMPPSuite) Test_processForm_returnsErrorFromCallback(c *C) {
18	e := errors.New("some kind of error")
19	f := &data.Form{}
20	_, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
21		c.Assert(len(fields), Equals, 0)
22		return e
23	})
24
25	c.Assert(err, Equals, e)
26}
27
28func (s *FormsXMPPSuite) Test_processForm_returnsEmptySubmitFormForEmptyForm(c *C) {
29	f := &data.Form{}
30	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
31		c.Assert(len(fields), Equals, 0)
32		return nil
33	})
34
35	c.Assert(err, IsNil)
36	c.Assert(*f2, DeepEquals, data.Form{Type: "submit"})
37}
38
39func (s *FormsXMPPSuite) Test_processForm_processButDoesNotReturnFixedFields(c *C) {
40	f := &data.Form{}
41	f.Fields = []data.FormFieldX{
42		data.FormFieldX{
43			Var:    "hello_field1",
44			Label:  "hello",
45			Type:   "fixed",
46			Values: []string{"Something"},
47		},
48		//Malformed
49		data.FormFieldX{
50			Var:   "hello_field2",
51			Label: "hello2",
52			Type:  "fixed",
53		},
54	}
55	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
56		c.Assert(len(fields), Equals, 1)
57		c.Assert(fields[0], DeepEquals, &data.FixedFormField{
58			FormField: data.FormField{
59				Name:  "hello_field1",
60				Label: "hello",
61				Type:  "fixed",
62			},
63			Text: "Something",
64		})
65		return nil
66	})
67
68	c.Assert(err, IsNil)
69	c.Assert(*f2, DeepEquals, data.Form{
70		Type:   "submit",
71		Fields: nil})
72}
73
74func (s *FormsXMPPSuite) Test_processForm_returnsBooleanFields(c *C) {
75	f := &data.Form{}
76	f.Fields = []data.FormFieldX{
77		data.FormFieldX{
78			Var:   "hello_field3",
79			Label: "hello3",
80			Type:  "boolean",
81		},
82	}
83	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
84		c.Assert(len(fields), Equals, 1)
85		c.Assert(fields[0], DeepEquals, &data.BooleanFormField{
86			FormField: data.FormField{
87				Name:  "hello_field3",
88				Label: "hello3",
89				Type:  "boolean",
90			},
91			Result: false,
92		})
93
94		return nil
95	})
96
97	c.Assert(err, IsNil)
98	c.Assert(*f2, DeepEquals, data.Form{
99		Type: "submit",
100		Fields: []data.FormFieldX{
101			data.FormFieldX{
102				Var:    "hello_field3",
103				Values: []string{"false"},
104			}}},
105	)
106}
107
108func (s *FormsXMPPSuite) Test_processForm_returnsMultiFields(c *C) {
109	f := &data.Form{}
110	f.Fields = []data.FormFieldX{
111		data.FormFieldX{
112			Var:   "hello_field4",
113			Label: "hello4",
114			Type:  "jid-multi",
115		},
116		data.FormFieldX{
117			Var:   "hello_field5",
118			Label: "hello5",
119			Type:  "text-multi",
120		},
121	}
122	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
123		c.Assert(len(fields), Equals, 2)
124
125		c.Assert(fields[0], DeepEquals, &data.MultiTextFormField{
126			FormField: data.FormField{
127				Name:  "hello_field4",
128				Label: "hello4",
129				Type:  "jid-multi",
130			},
131		})
132
133		c.Assert(fields[1], DeepEquals, &data.MultiTextFormField{
134			FormField: data.FormField{
135				Name:  "hello_field5",
136				Label: "hello5",
137				Type:  "text-multi",
138			},
139		})
140
141		return nil
142	})
143
144	c.Assert(err, IsNil)
145	c.Assert(*f2, DeepEquals, data.Form{
146		Type: "submit",
147		Fields: []data.FormFieldX{
148			data.FormFieldX{
149				Var: "hello_field4",
150			},
151			data.FormFieldX{
152				Var: "hello_field5",
153			},
154		}})
155}
156
157func (s *FormsXMPPSuite) Test_processForm_returnsListSingle(c *C) {
158	f := &data.Form{}
159	f.Fields = []data.FormFieldX{
160		data.FormFieldX{
161			Var:   "hello_field7",
162			Label: "hello7",
163			Type:  "list-single",
164			Options: []data.FormFieldOptionX{
165				data.FormFieldOptionX{Label: "One", Value: "Two"},
166				data.FormFieldOptionX{Label: "Three", Value: "Four"},
167			},
168
169			Values: []string{"Four"},
170		},
171	}
172	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
173		c.Assert(len(fields), Equals, 1)
174
175		c.Assert(fields[0], DeepEquals, &data.SelectionFormField{
176			FormField: data.FormField{
177				Name:  "hello_field7",
178				Label: "hello7",
179				Type:  "list-single",
180			},
181			Values: []string{"One", "Three"},
182			Ids:    []string{"Two", "Four"},
183			Result: 1,
184		})
185
186		return nil
187	})
188
189	c.Assert(err, IsNil)
190	c.Assert(f2, DeepEquals, &data.Form{
191		Type: "submit",
192		Fields: []data.FormFieldX{
193			data.FormFieldX{
194				Var:    "hello_field7",
195				Values: []string{"Four"},
196			},
197		}})
198}
199
200func (s *FormsXMPPSuite) Test_processForm_returnsListMulti(c *C) {
201	f := &data.Form{}
202	f.Fields = []data.FormFieldX{
203		data.FormFieldX{
204			Var:   "hello_field1o7",
205			Label: "hello1o7",
206			Type:  "list-multi",
207			Options: []data.FormFieldOptionX{
208				data.FormFieldOptionX{Label: "One", Value: "Two"},
209				data.FormFieldOptionX{Label: "Three", Value: "Four"},
210				data.FormFieldOptionX{Label: "Five", Value: "Six"},
211				data.FormFieldOptionX{Label: "Seven", Value: "Eight"},
212			},
213
214			Values: []string{"Six", "Two"},
215		},
216	}
217	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
218		c.Assert(len(fields), Equals, 1)
219
220		c.Assert(fields[0], DeepEquals, &data.MultiSelectionFormField{
221			FormField: data.FormField{
222				Name:  "hello_field1o7",
223				Label: "hello1o7",
224				Type:  "list-multi",
225			},
226			Values:  []string{"One", "Three", "Five", "Seven"},
227			Ids:     []string{"Two", "Four", "Six", "Eight"},
228			Results: []int{0, 2},
229		})
230
231		return nil
232	})
233
234	c.Assert(err, IsNil)
235	c.Assert(f2, DeepEquals, &data.Form{
236		Type: "submit",
237		Fields: []data.FormFieldX{
238			data.FormFieldX{
239				Var:    "hello_field1o7",
240				Values: []string{"Two", "Six"},
241			}}})
242}
243
244func (s *FormsXMPPSuite) Test_processForm_returnsHidden(c *C) {
245	f := &data.Form{}
246	f.Fields = []data.FormFieldX{
247		data.FormFieldX{
248			Var:    "hello_field1o71",
249			Label:  "hello1o71",
250			Type:   "hidden",
251			Values: []string{"secret"},
252		},
253	}
254	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
255		c.Assert(len(fields), Equals, 0)
256		return nil
257	})
258
259	c.Assert(err, IsNil)
260	c.Assert(*f2, DeepEquals, data.Form{
261		Type: "submit",
262		Fields: []data.FormFieldX{
263			data.FormFieldX{
264				Var:    "hello_field1o71",
265				Values: []string{"secret"},
266			}}})
267}
268
269func (s *FormsXMPPSuite) Test_processForm_returnsUnknown(c *C) {
270	f := &data.Form{}
271	f.Fields = []data.FormFieldX{
272		data.FormFieldX{
273			Var:   "hello_field1o71",
274			Label: "hello1o71",
275			Type:  "another-fancy-type",
276		},
277		data.FormFieldX{
278			Var:    "hello_field1o73",
279			Label:  "hello1o73",
280			Type:   "another-fancy-type",
281			Values: []string{"another one"},
282		},
283	}
284	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
285		c.Assert(len(fields), Equals, 2)
286
287		c.Assert(fields[0], DeepEquals, &data.TextFormField{
288			FormField: data.FormField{
289				Label: "hello1o71",
290				Type:  "another-fancy-type",
291				Name:  "hello_field1o71",
292			},
293		})
294
295		c.Assert(fields[1], DeepEquals, &data.TextFormField{
296			FormField: data.FormField{
297				Label: "hello1o73",
298				Type:  "another-fancy-type",
299				Name:  "hello_field1o73",
300			},
301			Default: "another one",
302		})
303
304		//The UI should set the value, and it should be available on the submit form
305		fields[0].(*data.TextFormField).Result = "Value from UI"
306
307		return nil
308	})
309
310	c.Assert(err, IsNil)
311	c.Assert(*f2, DeepEquals, data.Form{
312		Type: "submit",
313		Fields: []data.FormFieldX{
314			data.FormFieldX{
315				Var:    "hello_field1o71",
316				Values: []string{"Value from UI"},
317			},
318			data.FormFieldX{
319				Var:    "hello_field1o73",
320				Values: []string{""}, // Value is lost because the UI does not set anything. Expected.
321			}}})
322}
323
324type testOtherFormType struct{}
325
326func (s *FormsXMPPSuite) Test_processForm_panicsWhenGivenAWeirdFormType(c *C) {
327	f := &data.Form{}
328	f.Fields = []data.FormFieldX{
329		data.FormFieldX{
330			Label: "hello1o71",
331			Type:  "another-fancy-type",
332		},
333	}
334	c.Assert(func() {
335		processForm(f, nil, func(title, instructions string, fields []interface{}) error {
336			fields[0] = testOtherFormType{}
337			return nil
338		})
339	}, PanicMatches, "unknown field type in result from callback: xmpp.testOtherFormType")
340}
341
342func (s *FormsXMPPSuite) Test_processForm_setsAValidBooleanReturnValue(c *C) {
343	f := &data.Form{}
344	f.Fields = []data.FormFieldX{
345		data.FormFieldX{
346			Var:   "hello_field1o71",
347			Label: "hello1o71",
348			Type:  "boolean",
349		},
350	}
351	f2, _ := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
352		c.Assert(len(fields), Equals, 1)
353		fields[0].(*data.BooleanFormField).Result = true
354		return nil
355	})
356	c.Assert(*f2, DeepEquals, data.Form{
357		Type: "submit",
358		Fields: []data.FormFieldX{
359			data.FormFieldX{
360				XMLName: xml.Name{Space: "", Local: ""},
361				Var:     "hello_field1o71",
362				Values:  []string{"true"},
363			}}})
364}
365
366func (s *FormsXMPPSuite) Test_processForm_returnsListMultiWithResults(c *C) {
367	f := &data.Form{}
368	f.Fields = []data.FormFieldX{
369		data.FormFieldX{
370			Var:   "hello_field1o7",
371			Label: "hello1o7",
372			Type:  "list-multi",
373			Options: []data.FormFieldOptionX{
374				data.FormFieldOptionX{Label: "One", Value: "Two"},
375				data.FormFieldOptionX{Label: "Three", Value: "Four"},
376			},
377		},
378	}
379	f2, err := processForm(f, nil, func(title, instructions string, fields []interface{}) error {
380		c.Assert(len(fields), Equals, 1)
381		fields[0].(*data.MultiSelectionFormField).Results = []int{1}
382		return nil
383	})
384
385	c.Assert(err, IsNil)
386	c.Assert(*f2, DeepEquals, data.Form{
387		Type: "submit",
388		Fields: []data.FormFieldX{
389			data.FormFieldX{
390				Var:    "hello_field1o7",
391				Values: []string{"Four"},
392			}}})
393}
394
395func (s *FormsXMPPSuite) Test_processForm_dealsWithMediaCorrectly(c *C) {
396	fooBarDecoded := []byte("hello world")
397	f := &data.Form{}
398	datas := []data.BobData{
399		data.BobData{
400			CID:    "foobax",
401			Base64: ".....",
402		},
403		data.BobData{
404			CID:    "foobar",
405			Base64: base64.StdEncoding.EncodeToString(fooBarDecoded),
406		},
407	}
408	f.Fields = []data.FormFieldX{
409		data.FormFieldX{
410			Var:    "hello1",
411			Label:  "hello",
412			Type:   "fixed",
413			Values: []string{"Something"},
414			Media: []data.FormFieldMediaX{
415				data.FormFieldMediaX{
416					URIs: []data.MediaURIX{
417						data.MediaURIX{
418							MIMEType: "application/not-a-uri",
419							URI:      "",
420						},
421						data.MediaURIX{
422							MIMEType: "application/not-a-cid-uri",
423							URI:      "hello:world",
424						},
425						data.MediaURIX{
426							MIMEType: "application/valid-encoding",
427							URI:      "cid:foobar",
428						},
429						data.MediaURIX{
430							MIMEType: "application/invalid-encoding",
431							URI:      "cid:foobax",
432						},
433					},
434				},
435			},
436		},
437		data.FormFieldX{
438			Var:   "hello2",
439			Label: "hello1o7",
440			Type:  "hidden",
441			Media: []data.FormFieldMediaX{
442				data.FormFieldMediaX{
443					URIs: []data.MediaURIX{
444						data.MediaURIX{
445							MIMEType: "application/does-not-matter-because-it-is-ignored",
446							URI:      "hello:world",
447						},
448						data.MediaURIX{
449							MIMEType: "application/does-not-matter-because-it-is-also-ignored",
450							URI:      "cid:foobax",
451						},
452					},
453				},
454			},
455		},
456	}
457
458	f2, err := processForm(f, datas, func(title, instructions string, fields []interface{}) error {
459		//NOTE: hidden fields are not passed to the callback so you can't have access to any media
460		//in hidden fields.
461		c.Assert(len(fields), Equals, 1)
462		c.Assert(fields[0], DeepEquals, &data.FixedFormField{
463			FormField: data.FormField{
464				Name:  "hello1",
465				Label: "hello",
466				Type:  "fixed",
467				Media: [][]data.Media{
468					[]data.Media{
469						data.Media{
470							MIMEType: "application/not-a-cid-uri",
471							URI:      "hello:world",
472						},
473						data.Media{
474							MIMEType: "application/valid-encoding",
475							Data:     fooBarDecoded,
476						},
477					}},
478			},
479			Text: "Something",
480		})
481		return nil
482	})
483
484	c.Assert(err, IsNil)
485	c.Assert(*f2, DeepEquals, data.Form{
486		Type: "submit",
487		Fields: []data.FormFieldX{
488			data.FormFieldX{
489				Var: "hello2",
490			}}})
491}
492