1package imap 2 3import ( 4 "bytes" 5 "io" 6 "net/textproto" 7 "reflect" 8 "strings" 9 "testing" 10 "time" 11) 12 13// Note to myself: writing these boring tests actually fixed 2 bugs :P 14 15var searchSeqSet1, _ = ParseSeqSet("1:42") 16var searchSeqSet2, _ = ParseSeqSet("743:938") 17var searchDate1 = time.Date(1997, 11, 21, 0, 0, 0, 0, time.UTC) 18var searchDate2 = time.Date(1984, 11, 5, 0, 0, 0, 0, time.UTC) 19 20var searchCriteriaTests = []struct { 21 expected string 22 criteria *SearchCriteria 23}{ 24 { 25 expected: `(1:42 UID 743:938 ` + 26 `SINCE "5-Nov-1984" BEFORE "21-Nov-1997" SENTSINCE "5-Nov-1984" SENTBEFORE "21-Nov-1997" ` + 27 `FROM "root@protonmail.com" BODY "hey there" TEXT "DILLE" ` + 28 `ANSWERED DELETED KEYWORD cc UNKEYWORD microsoft ` + 29 `LARGER 4242 SMALLER 4342 ` + 30 `NOT (SENTON "21-Nov-1997" HEADER "Content-Type" "text/csv") ` + 31 `OR (ON "5-Nov-1984" DRAFT FLAGGED UNANSWERED UNDELETED OLD) (UNDRAFT UNFLAGGED UNSEEN))`, 32 criteria: &SearchCriteria{ 33 SeqNum: searchSeqSet1, 34 Uid: searchSeqSet2, 35 Since: searchDate2, 36 Before: searchDate1, 37 SentSince: searchDate2, 38 SentBefore: searchDate1, 39 Header: textproto.MIMEHeader{ 40 "From": {"root@protonmail.com"}, 41 }, 42 Body: []string{"hey there"}, 43 Text: []string{"DILLE"}, 44 WithFlags: []string{AnsweredFlag, DeletedFlag, "cc"}, 45 WithoutFlags: []string{"microsoft"}, 46 Larger: 4242, 47 Smaller: 4342, 48 Not: []*SearchCriteria{{ 49 SentSince: searchDate1, 50 SentBefore: searchDate1.Add(24 * time.Hour), 51 Header: textproto.MIMEHeader{ 52 "Content-Type": {"text/csv"}, 53 }, 54 }}, 55 Or: [][2]*SearchCriteria{{ 56 { 57 Since: searchDate2, 58 Before: searchDate2.Add(24 * time.Hour), 59 WithFlags: []string{DraftFlag, FlaggedFlag}, 60 WithoutFlags: []string{AnsweredFlag, DeletedFlag, RecentFlag}, 61 }, 62 { 63 WithoutFlags: []string{DraftFlag, FlaggedFlag, SeenFlag}, 64 }, 65 }}, 66 }, 67 }, 68 { 69 expected: "(ALL)", 70 criteria: &SearchCriteria{}, 71 }, 72} 73 74func TestSearchCriteria_Format(t *testing.T) { 75 for i, test := range searchCriteriaTests { 76 fields := test.criteria.Format() 77 78 got, err := formatFields(fields) 79 if err != nil { 80 t.Fatal("Unexpected no error while formatting fields, got:", err) 81 } 82 83 if got != test.expected { 84 t.Errorf("Invalid search criteria fields for #%v: got \n%v\n instead of \n%v", i+1, got, test.expected) 85 } 86 } 87} 88 89func TestSearchCriteria_Parse(t *testing.T) { 90 for i, test := range searchCriteriaTests { 91 criteria := new(SearchCriteria) 92 93 b := bytes.NewBuffer([]byte(test.expected)) 94 r := NewReader(b) 95 fields, _ := r.ReadFields() 96 97 if err := criteria.ParseWithCharset(fields[0].([]interface{}), nil); err != nil { 98 t.Errorf("Cannot parse search criteria for #%v: %v", i+1, err) 99 } else if !reflect.DeepEqual(criteria, test.criteria) { 100 t.Errorf("Invalid search criteria for #%v: got \n%+v\n instead of \n%+v", i+1, criteria, test.criteria) 101 } 102 } 103} 104 105var searchCriteriaParseTests = []struct { 106 fields []interface{} 107 criteria *SearchCriteria 108 charset func(io.Reader) io.Reader 109}{ 110 { 111 fields: []interface{}{"ALL"}, 112 criteria: &SearchCriteria{}, 113 }, 114 { 115 fields: []interface{}{"NEW"}, 116 criteria: &SearchCriteria{ 117 WithFlags: []string{RecentFlag}, 118 WithoutFlags: []string{SeenFlag}, 119 }, 120 }, 121 { 122 fields: []interface{}{"SUBJECT", strings.NewReader("café")}, 123 criteria: &SearchCriteria{ 124 Header: textproto.MIMEHeader{"Subject": {"café"}}, 125 }, 126 charset: func(r io.Reader) io.Reader { 127 return r 128 }, 129 }, 130} 131 132func TestSearchCriteria_Parse_others(t *testing.T) { 133 for i, test := range searchCriteriaParseTests { 134 criteria := new(SearchCriteria) 135 if err := criteria.ParseWithCharset(test.fields, test.charset); err != nil { 136 t.Errorf("Cannot parse search criteria for #%v: %v", i+1, err) 137 } else if !reflect.DeepEqual(criteria, test.criteria) { 138 t.Errorf("Invalid search criteria for #%v: got \n%+v\n instead of \n%+v", i+1, criteria, test.criteria) 139 } 140 } 141} 142