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  }