github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/search/utils_test.go (about) 1 package search 2 3 import ( 4 "strings" 5 "testing" 6 "time" 7 8 "github.com/keybase/client/go/externalstest" 9 "github.com/keybase/client/go/protocol/chat1" 10 "github.com/keybase/client/go/protocol/gregor1" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestTokenize(t *testing.T) { 15 tc := externalstest.SetupTest(t, "tokenize", 2) 16 defer tc.Cleanup() 17 supportedSplit := []string{ 18 ".", 19 ",", 20 "?", 21 "!", 22 " ", 23 "\n", 24 } 25 // make sure we split correctly for various separators we support and stem 26 // on basic examples 27 for _, sep := range supportedSplit { 28 msgText := strings.Join([]string{ 29 // groupings 30 "(hello1)", 31 "[hello2]", 32 "<hello3>", 33 "{hello4}", 34 // phone 35 "(123)-456-7890", 36 "(234).567.8901", 37 "(345) 678 9012", 38 "456-789-0123", 39 // mentions 40 "@hello5", 41 "#hello6", 42 // usernames 43 "blumua@twitter", 44 // markdown 45 "*hello7*", 46 "~hello8~", 47 "_hello9_", 48 `"hello10"`, 49 "'hello11'", 50 // stem 51 "wanted", 52 "italy's", 53 "looking", 54 // utf8 55 "约书亚和约翰屌爆", 56 // emoji 57 ":+1:", 58 }, sep) 59 tokens := tokenize(msgText) 60 t.Logf("msgText: %v, tokens: %v", msgText, tokens) 61 require.Equal(t, tokenMap{ 62 "\"hello10\"": map[string]chat1.EmptyStruct{ 63 "hel": {}, 64 "hell": {}, 65 "hello": {}, 66 "hello1": {}, 67 "hello10": {}, 68 }, 69 "#hello6": map[string]chat1.EmptyStruct{ 70 "hel": {}, 71 "hell": {}, 72 "hello": {}, 73 "hello6": {}, 74 }, 75 "'hello11'": map[string]chat1.EmptyStruct{ 76 "hel": {}, 77 "hell": {}, 78 "hello": {}, 79 "hello1": {}, 80 "hello11": {}, 81 }, 82 "(123)-456-7890": map[string]chat1.EmptyStruct{ 83 "123": {}, 84 "456": {}, 85 "789": {}, 86 "7890": {}, 87 }, 88 "(hello1)": map[string]chat1.EmptyStruct{ 89 "hel": {}, 90 "hell": {}, 91 "hello": {}, 92 "hello1": {}, 93 }, 94 "*hello7*": map[string]chat1.EmptyStruct{ 95 "hel": {}, 96 "hell": {}, 97 "hello": {}, 98 "hello7": {}, 99 }, 100 "456-789-0123": map[string]chat1.EmptyStruct{ 101 "456": {}, 102 "789": {}, 103 "0123": {}, 104 "012": {}, 105 }, 106 "(234)": map[string]chat1.EmptyStruct{ 107 "234": {}, 108 }, 109 "(345)": map[string]chat1.EmptyStruct{ 110 "345": {}, 111 }, 112 "567": map[string]chat1.EmptyStruct{}, 113 "678": map[string]chat1.EmptyStruct{}, 114 "8901": map[string]chat1.EmptyStruct{ 115 "890": {}, 116 }, 117 "9012": map[string]chat1.EmptyStruct{ 118 "901": {}, 119 }, 120 ":+1:": map[string]chat1.EmptyStruct{ 121 ":+1": {}, 122 }, 123 "<hello3>": map[string]chat1.EmptyStruct{ 124 "hel": {}, 125 "hell": {}, 126 "hello": {}, 127 "hello3": {}, 128 }, 129 "@hello5": map[string]chat1.EmptyStruct{ 130 "hel": {}, 131 "hell": {}, 132 "hello": {}, 133 "hello5": {}, 134 }, 135 "[hello2]": map[string]chat1.EmptyStruct{ 136 "hel": {}, 137 "hell": {}, 138 "hello": {}, 139 "hello2": {}, 140 }, 141 "_hello9_": map[string]chat1.EmptyStruct{ 142 "hel": {}, 143 "hell": {}, 144 "hello": {}, 145 "hello9": {}, 146 }, 147 "blumua@twitter": map[string]chat1.EmptyStruct{ 148 "blu": {}, 149 "blum": {}, 150 "blumu": {}, 151 "blumua": {}, 152 "twi": {}, 153 "twit": {}, 154 "twitt": {}, 155 "twitte": {}, 156 "twitter": {}, 157 }, 158 "italy's": map[string]chat1.EmptyStruct{ 159 "ita": {}, 160 "ital": {}, 161 "itali": {}, 162 "italy": {}, 163 "s": {}, 164 }, 165 "looking": map[string]chat1.EmptyStruct{ 166 "loo": {}, 167 "look": {}, 168 "looki": {}, 169 "lookin": {}, 170 }, 171 "wanted": map[string]chat1.EmptyStruct{ 172 "wan": {}, 173 "want": {}, 174 "wante": {}, 175 }, 176 "{hello4}": map[string]chat1.EmptyStruct{ 177 "hel": {}, 178 "hell": {}, 179 "hello": {}, 180 "hello4": {}, 181 }, 182 "~hello8~": map[string]chat1.EmptyStruct{ 183 "hel": {}, 184 "hell": {}, 185 "hello": {}, 186 "hello8": {}, 187 }, 188 "约书亚和约翰屌爆": map[string]chat1.EmptyStruct{ 189 "约": {}, 190 "约书": {}, 191 "约书亚": {}, 192 }, 193 }, tokens) 194 } 195 // empty case 196 require.Nil(t, tokenize("")) 197 } 198 199 func TestUpgradeSearchOptsFromQuery(t *testing.T) { 200 username := "mikem" 201 sentByCase := func(query, resQuery, resSentBy string) { 202 query, opts := UpgradeSearchOptsFromQuery(query, chat1.SearchOpts{}, username) 203 require.Equal(t, resQuery, query) 204 require.Equal(t, resSentBy, opts.SentBy) 205 } 206 sentByCase("from:karenm hi mike", "hi mike", "karenm") 207 sentByCase("from:@karenm hi mike", "hi mike", "karenm") 208 sentByCase("from:@karenm hi mike ", "hi mike", "karenm") 209 sentByCase("from: hi mike", "from: hi mike", "") 210 sentByCase("hi mike from:karenm", "hi mike", "karenm") 211 sentByCase("from:me hi mike", "hi mike", "mikem") 212 213 sentToCase := func(query, resQuery, resSentTo string) { 214 query, opts := UpgradeSearchOptsFromQuery(query, chat1.SearchOpts{}, username) 215 require.Equal(t, resQuery, query) 216 require.Equal(t, resSentTo, opts.SentTo) 217 } 218 sentToCase("to:karenm hi mike", "hi mike", "karenm") 219 sentToCase("to:@karenm hi mike", "hi mike", "karenm") 220 sentToCase("to:@karenm hi mike ", "hi mike", "karenm") 221 sentToCase("to: hi mike", "to: hi mike", "") 222 sentToCase("hi mike to:karenm", "hi mike", "karenm") 223 sentToCase("to:me hi mike", "hi mike", "mikem") 224 225 regexpCase := func(query, resQuery string, isRegex bool) { 226 query, opts := UpgradeSearchOptsFromQuery(query, chat1.SearchOpts{}, username) 227 require.Equal(t, resQuery, query) 228 require.Equal(t, isRegex, opts.IsRegex) 229 } 230 regexpCase("/", "/", false) 231 regexpCase("//", "//", false) 232 regexpCase("/mike.*always/", "mike.*always", true) 233 regexpCase("X/mike.*always/", "X/mike.*always/", false) 234 235 dateFilterCase := func(query, resQuery string, sentBefore, sentAfter gregor1.Time) { 236 query, opts := UpgradeSearchOptsFromQuery(query, chat1.SearchOpts{}, username) 237 require.Equal(t, resQuery, query) 238 require.Equal(t, sentBefore, opts.SentBefore) 239 require.Equal(t, sentAfter, opts.SentAfter) 240 } 241 parsed, err := time.Parse(time.RFC822, "16 Mar 18 00:00 UTC") 242 require.NoError(t, err) 243 expectedTime := gregor1.ToTime(parsed) 244 dateFilterCase("before:2018-03-16 hi mike", "hi mike", expectedTime, 0) 245 dateFilterCase("before:3/16/18 hi mike", "hi mike", expectedTime, 0) 246 dateFilterCase("before:3.16.18 hi mike", "hi mike", expectedTime, 0) 247 dateFilterCase("before:03/16/2018 hi mike", "hi mike", expectedTime, 0) 248 dateFilterCase("after:2018-03-16 hi mike", "hi mike", 0, expectedTime) 249 dateFilterCase("before:2018-03-16 after:2018-03-16 hi mike", "hi mike", expectedTime, expectedTime) 250 dateFilterCase("before:2018 after:asdf hi mike", "before:2018 after:asdf hi mike", 0, 0) 251 252 // the whole shabang 253 query, opts := UpgradeSearchOptsFromQuery("from:karenm to:mikem before:2018-03-16 after:3/16/18 /Lisa.*something/", 254 chat1.SearchOpts{}, username) 255 require.Equal(t, "Lisa.*something", query) 256 require.Equal(t, "karenm", opts.SentBy) 257 require.Equal(t, "mikem", opts.SentTo) 258 require.Equal(t, expectedTime, opts.SentBefore) 259 require.Equal(t, expectedTime, opts.SentBefore) 260 require.True(t, opts.IsRegex) 261 262 }