form - form_test.go
1 package form
2
3 import (
4 "io"
5 "math"
6 "net/http"
7 "net/url"
8 "reflect"
9 "regexp"
10 "strings"
11 "testing"
12 )
13
14 type Z struct {
15 C int
16 Y
17 }
18
19 type Y struct {
20 X
21 B bool
22 }
23
24 type X struct {
25 A string
26 }
27
28 func TestCreateTypeMap(t *testing.T) {
29 for n, test := range [...]struct {
30 Input reflect.Type
31 Output typeMap
32 }{
33 { // 1
34 Input: reflect.TypeOf(struct {
35 A int
36 }{}),
37 Output: typeMap{
38 "A": {
39 processor: inum{
40 bits: 64,
41 min: math.MinInt64,
42 max: math.MaxInt64,
43 },
44 Index: []int{0},
45 },
46 },
47 },
48 { // 2
49 Input: reflect.TypeOf(struct {
50 A int `form:"B"`
51 }{}),
52 Output: typeMap{
53 "B": {
54 processor: inum{
55 bits: 64,
56 min: math.MinInt64,
57 max: math.MaxInt64,
58 },
59 Index: []int{0},
60 },
61 },
62 },
63 { // 3
64 Input: reflect.TypeOf(struct {
65 A int `form:",required"`
66 }{}),
67 Output: typeMap{
68 "A": {
69 processor: inum{
70 bits: 64,
71 min: math.MinInt64,
72 max: math.MaxInt64,
73 },
74 Required: true,
75 Index: []int{0},
76 },
77 },
78 },
79 { // 4
80 Input: reflect.TypeOf(struct {
81 A int `form:",post"`
82 }{}),
83 Output: typeMap{
84 "A": {
85 processor: inum{
86 bits: 64,
87 min: math.MinInt64,
88 max: math.MaxInt64,
89 },
90 Post: true,
91 Index: []int{0},
92 },
93 },
94 },
95 { // 5
96 Input: reflect.TypeOf(struct {
97 A int `form:",post,required"`
98 }{}),
99 Output: typeMap{
100 "A": {
101 processor: inum{
102 bits: 64,
103 min: math.MinInt64,
104 max: math.MaxInt64,
105 },
106 Post: true,
107 Required: true,
108 Index: []int{0},
109 },
110 },
111 },
112 { // 6
113 Input: reflect.TypeOf(struct {
114 A int `form:",required,post"`
115 }{}),
116 Output: typeMap{
117 "A": {
118 processor: inum{
119 bits: 64,
120 min: math.MinInt64,
121 max: math.MaxInt64,
122 },
123 Post: true,
124 Required: true,
125 Index: []int{0},
126 },
127 },
128 },
129 { // 7
130 Input: reflect.TypeOf(struct {
131 A int `min:"-20"`
132 }{}),
133 Output: typeMap{
134 "A": {
135 processor: inum{
136 bits: 64,
137 min: -20,
138 max: math.MaxInt64,
139 },
140 Index: []int{0},
141 },
142 },
143 },
144 { // 8
145 Input: reflect.TypeOf(struct {
146 A int `max:"-20"`
147 }{}),
148 Output: typeMap{
149 "A": {
150 processor: inum{
151 bits: 64,
152 min: math.MinInt64,
153 max: -20,
154 },
155 Index: []int{0},
156 },
157 },
158 },
159 { // 9
160 Input: reflect.TypeOf(struct {
161 A int8
162 }{}),
163 Output: typeMap{
164 "A": {
165 processor: inum{
166 bits: 8,
167 min: math.MinInt64,
168 max: math.MaxInt64,
169 },
170 Index: []int{0},
171 },
172 },
173 },
174 { // 10
175 Input: reflect.TypeOf(struct {
176 A int16
177 }{}),
178 Output: typeMap{
179 "A": {
180 processor: inum{
181 bits: 16,
182 min: math.MinInt64,
183 max: math.MaxInt64,
184 },
185 Index: []int{0},
186 },
187 },
188 },
189 { // 11
190 Input: reflect.TypeOf(struct {
191 A int32
192 }{}),
193 Output: typeMap{
194 "A": {
195 processor: inum{
196 bits: 32,
197 min: math.MinInt64,
198 max: math.MaxInt64,
199 },
200 Index: []int{0},
201 },
202 },
203 },
204 { // 12
205 Input: reflect.TypeOf(struct {
206 A int64
207 }{}),
208 Output: typeMap{
209 "A": {
210 processor: inum{
211 bits: 64,
212 min: math.MinInt64,
213 max: math.MaxInt64,
214 },
215 Index: []int{0},
216 },
217 },
218 },
219 { // 13
220 Input: reflect.TypeOf(struct {
221 A uint
222 }{}),
223 Output: typeMap{
224 "A": {
225 processor: unum{
226 bits: 64,
227 max: math.MaxUint64,
228 },
229 Index: []int{0},
230 },
231 },
232 },
233 { // 14
234 Input: reflect.TypeOf(struct {
235 A uint `min:"10"`
236 }{}),
237 Output: typeMap{
238 "A": {
239 processor: unum{
240 bits: 64,
241 min: 10,
242 max: math.MaxUint64,
243 },
244 Index: []int{0},
245 },
246 },
247 },
248 { // 15
249 Input: reflect.TypeOf(struct {
250 A uint `min:"-1"`
251 }{}),
252 Output: typeMap{
253 "A": {
254 processor: unum{
255 bits: 64,
256 max: math.MaxUint64,
257 },
258 Index: []int{0},
259 },
260 },
261 },
262 { // 16
263 Input: reflect.TypeOf(struct {
264 A uint `max:"100"`
265 }{}),
266 Output: typeMap{
267 "A": {
268 processor: unum{
269 bits: 64,
270 max: 100,
271 },
272 Index: []int{0},
273 },
274 },
275 },
276 { // 17
277 Input: reflect.TypeOf(struct {
278 A uint8
279 }{}),
280 Output: typeMap{
281 "A": {
282 processor: unum{
283 bits: 8,
284 max: math.MaxUint64,
285 },
286 Index: []int{0},
287 },
288 },
289 },
290 { // 18
291 Input: reflect.TypeOf(struct {
292 A uint16
293 }{}),
294 Output: typeMap{
295 "A": {
296 processor: unum{
297 bits: 16,
298 max: math.MaxUint64,
299 },
300 Index: []int{0},
301 },
302 },
303 },
304 { // 19
305 Input: reflect.TypeOf(struct {
306 A uint32
307 }{}),
308 Output: typeMap{
309 "A": {
310 processor: unum{
311 bits: 32,
312 max: math.MaxUint64,
313 },
314 Index: []int{0},
315 },
316 },
317 },
318 { // 20
319 Input: reflect.TypeOf(struct {
320 A uint
321 }{}),
322 Output: typeMap{
323 "A": {
324 processor: unum{
325 bits: 64,
326 max: math.MaxUint64,
327 },
328 Index: []int{0},
329 },
330 },
331 },
332 { // 21
333 Input: reflect.TypeOf(struct {
334 A float32
335 }{}),
336 Output: typeMap{
337 "A": {
338 processor: float{
339 bits: 32,
340 min: -math.MaxFloat64,
341 max: math.MaxFloat64,
342 },
343 Index: []int{0},
344 },
345 },
346 },
347 { // 22
348 Input: reflect.TypeOf(struct {
349 A float64
350 }{}),
351 Output: typeMap{
352 "A": {
353 processor: float{
354 bits: 64,
355 min: -math.MaxFloat64,
356 max: math.MaxFloat64,
357 },
358 Index: []int{0},
359 },
360 },
361 },
362 { // 23
363 Input: reflect.TypeOf(struct {
364 A float64 `min:"-10"`
365 }{}),
366 Output: typeMap{
367 "A": {
368 processor: float{
369 bits: 64,
370 min: -10,
371 max: math.MaxFloat64,
372 },
373 Index: []int{0},
374 },
375 },
376 },
377 { // 24
378 Input: reflect.TypeOf(struct {
379 A float64 `max:"10"`
380 }{}),
381 Output: typeMap{
382 "A": {
383 processor: float{
384 bits: 64,
385 min: -math.MaxFloat64,
386 max: 10,
387 },
388 Index: []int{0},
389 },
390 },
391 },
392 { // 25
393 Input: reflect.TypeOf(struct {
394 A string
395 }{}),
396 Output: typeMap{
397 "A": {
398 processor: str{},
399 Index: []int{0},
400 },
401 },
402 },
403 { // 26
404 Input: reflect.TypeOf(struct {
405 A string `regex:"/aaa/"`
406 }{}),
407 Output: typeMap{
408 "A": {
409 processor: str{
410 regex: regexp.MustCompile("/aaa/"),
411 },
412 Index: []int{0},
413 },
414 },
415 },
416 { // 27
417 Input: reflect.TypeOf(struct {
418 A bool
419 }{}),
420 Output: typeMap{
421 "A": {
422 processor: boolean{},
423 Index: []int{0},
424 },
425 },
426 },
427 { // 28
428 Input: reflect.TypeOf(struct {
429 A []bool
430 }{}),
431 Output: typeMap{
432 "A": {
433 processor: slice{
434 processor: boolean{},
435 typ: reflect.TypeOf([]bool{}),
436 },
437 Index: []int{0},
438 },
439 },
440 },
441 { // 29
442 Input: reflect.TypeOf(struct {
443 A []int `min:"10"`
444 }{}),
445 Output: typeMap{
446 "A": {
447 processor: slice{
448 processor: inum{
449 min: 10,
450 max: math.MaxInt64,
451 bits: 64,
452 },
453 typ: reflect.TypeOf([]int{}),
454 },
455 Index: []int{0},
456 },
457 },
458 },
459 { // 30
460 Input: reflect.TypeOf(struct {
461 X
462 }{}),
463 Output: typeMap{
464 "A": {
465 processor: str{},
466 Index: []int{0, 0},
467 },
468 },
469 },
470 { // 31
471 Input: reflect.TypeOf(struct {
472 X
473 A bool
474 }{}),
475 Output: typeMap{
476 "A": {
477 processor: boolean{},
478 Index: []int{1},
479 },
480 },
481 },
482 } {
483 output := createTypeMap(test.Input)
484 if !reflect.DeepEqual(output, test.Output) {
485 t.Errorf("test %d: expecting output %v, got %v", n+1, test.Output, output)
486 }
487 }
488 }
489
490 func TestProcess(t *testing.T) {
491 for n, test := range [...]struct {
492 Get, Post url.Values
493 Output interface{}
494 Err error
495 }{
496 { // 1
497 url.Values{
498 "A": []string{"1"},
499 },
500 url.Values{},
501 struct {
502 A int
503 }{
504 A: 1,
505 },
506 nil,
507 },
508 { // 2
509 url.Values{},
510 url.Values{
511 "A": []string{"1"},
512 },
513 struct {
514 A int
515 }{
516 A: 1,
517 },
518 nil,
519 },
520 { // 3
521 url.Values{
522 "A": []string{"1"},
523 },
524 url.Values{
525 "A": []string{"2"},
526 },
527 struct {
528 A int `form:",post"`
529 }{
530 A: 2,
531 },
532 nil,
533 },
534 { // 4
535 url.Values{},
536 url.Values{},
537 struct {
538 A int `form:",required"`
539 }{},
540 ErrorMap{
541 "A": ErrRequiredMissing,
542 },
543 },
544 { // 5
545 url.Values{
546 "B": []string{"10"},
547 },
548 url.Values{},
549 struct {
550 A int `form:"B"`
551 }{
552 A: 10,
553 },
554 nil,
555 },
556 { // 6
557 url.Values{
558 "A": []string{"10"},
559 },
560 url.Values{},
561 struct {
562 A int `min:"15"`
563 }{},
564 ErrorMap{
565 "A": ErrNotInRange,
566 },
567 },
568 { // 7
569 url.Values{
570 "A": []string{"10"},
571 },
572 url.Values{},
573 struct {
574 A int `max:"5"`
575 }{},
576 ErrorMap{
577 "A": ErrNotInRange,
578 },
579 },
580 { // 8
581 url.Values{
582 "A": []string{"10"},
583 },
584 url.Values{},
585 struct {
586 A int `min:"5" max:"15"`
587 }{
588 A: 10,
589 },
590 nil,
591 },
592 { // 9
593 url.Values{
594 "A": []string{"10"},
595 },
596 url.Values{},
597 struct {
598 A uint `min:"15"`
599 }{},
600 ErrorMap{
601 "A": ErrNotInRange,
602 },
603 },
604 { // 10
605 url.Values{
606 "A": []string{"10"},
607 },
608 url.Values{},
609 struct {
610 A uint `max:"5"`
611 }{},
612 ErrorMap{
613 "A": ErrNotInRange,
614 },
615 },
616 { // 11
617 url.Values{
618 "A": []string{"10"},
619 },
620 url.Values{},
621 struct {
622 A uint `min:"5" max:"15"`
623 }{
624 A: 10,
625 },
626 nil,
627 },
628 { // 12
629 url.Values{
630 "A": []string{"true"},
631 },
632 url.Values{},
633 struct {
634 A bool
635 }{
636 A: true,
637 },
638 nil,
639 },
640 { // 13
641 url.Values{
642 "A": []string{"false"},
643 },
644 url.Values{},
645 struct {
646 A bool
647 }{},
648 nil,
649 },
650 { // 14
651 url.Values{
652 "A": []string{"tRuE"},
653 },
654 url.Values{},
655 struct {
656 A bool
657 }{
658 A: true,
659 },
660 nil,
661 },
662 { // 15
663 url.Values{
664 "A": []string{"fAlSe"},
665 },
666 url.Values{},
667 struct {
668 A bool
669 }{},
670 nil,
671 },
672 { // 16
673 url.Values{
674 "A": []string{"ON"},
675 },
676 url.Values{},
677 struct {
678 A bool
679 }{
680 A: true,
681 },
682 nil,
683 },
684 { // 17
685 url.Values{
686 "A": []string{"OFF"},
687 },
688 url.Values{},
689 struct {
690 A bool
691 }{},
692 nil,
693 },
694 { // 18
695 url.Values{
696 "A": []string{"!"},
697 },
698 url.Values{},
699 struct {
700 A bool
701 }{},
702 ErrorMap{
703 "A": ErrInvalidBoolean,
704 },
705 },
706 { // 19
707 url.Values{
708 "A": []string{"10"},
709 },
710 url.Values{},
711 struct {
712 A float64 `min:"15"`
713 }{},
714 ErrorMap{
715 "A": ErrNotInRange,
716 },
717 },
718 { // 20
719 url.Values{
720 "A": []string{"10"},
721 },
722 url.Values{},
723 struct {
724 A float64 `max:"5"`
725 }{},
726 ErrorMap{
727 "A": ErrNotInRange,
728 },
729 },
730 { // 21
731 url.Values{
732 "A": []string{"10.5"},
733 },
734 url.Values{},
735 struct {
736 A float64 `min:"5.5" max:"15.5"`
737 }{
738 A: 10.5,
739 },
740 nil,
741 },
742 { // 22
743 url.Values{
744 "A": []string{"HELLO, WORLD"},
745 },
746 url.Values{},
747 struct {
748 A string
749 }{
750 A: "HELLO, WORLD",
751 },
752 nil,
753 },
754 { // 23
755 url.Values{
756 "A": []string{"HELLO, WORLD"},
757 },
758 url.Values{},
759 struct {
760 A string `regex:"HELLO"`
761 }{
762 A: "HELLO, WORLD",
763 },
764 nil,
765 },
766 { // 24
767 url.Values{
768 "A": []string{"HELLO, WORLD"},
769 },
770 url.Values{},
771 struct {
772 A string `regex:"hello"`
773 }{},
774 ErrorMap{
775 "A": ErrNoMatch,
776 },
777 },
778 { // 25
779 url.Values{
780 "A": []string{"HELLO, WORLD"},
781 },
782 url.Values{},
783 struct {
784 A []string
785 }{
786 A: []string{"HELLO, WORLD"},
787 },
788 nil,
789 },
790 { // 26
791 url.Values{
792 "A": []string{"HELLO, WORLD", "Beep, Beep"},
793 },
794 url.Values{},
795 struct {
796 A []string
797 }{
798 A: []string{
799 "HELLO, WORLD",
800 "Beep, Beep",
801 },
802 },
803 nil,
804 },
805 { // 26
806 url.Values{
807 "A": []string{"HELLO, WORLD", "Beep, Beep"},
808 },
809 url.Values{},
810 struct {
811 A []string `regex:"Beep"`
812 }{
813 A: []string{
814 "",
815 "Beep, Beep",
816 },
817 },
818 ErrorMap{
819 "A": Errors{
820 ErrNoMatch,
821 nil,
822 },
823 },
824 },
825 { // 27
826 url.Values{
827 "A": []string{"123"},
828 "B": []string{"Y"},
829 "C": []string{"10"},
830 },
831 url.Values{},
832 struct {
833 Z
834 }{
835 Z: Z{
836 C: 10,
837 Y: Y{
838 X: X{
839 A: "123",
840 },
841 B: true,
842 },
843 },
844 },
845 nil,
846 },
847 } {
848 r := http.Request{
849 Method: http.MethodPost,
850 URL: &url.URL{
851 RawQuery: test.Get.Encode(),
852 },
853 Header: http.Header{
854 "Content-Type": []string{"application/x-www-form-urlencoded"},
855 },
856 Body: io.NopCloser(strings.NewReader(test.Post.Encode())),
857 }
858 output := reflect.New(reflect.TypeOf(test.Output))
859 err := Process(&r, output.Interface())
860 if err != nil {
861 if test.Err == nil {
862 t.Errorf("test %d: unexpected error: %s", n+1, err)
863 } else if !reflect.DeepEqual(err, test.Err) {
864 t.Errorf("test %d: expecting error: %s\ngot: %s", n+1, test.Err, err)
865 }
866 } else if test.Err != nil {
867 t.Errorf("test %d: got no error when expecting: %s", n+1, test.Err)
868 }
869 if o := output.Elem().Interface(); !reflect.DeepEqual(o, test.Output) {
870 t.Errorf("test %d: expecting output: %#v\ngot: %#v", n+1, test.Output, o)
871 }
872 }
873 }
874