src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/mods/doc/match_test.go (about) 1 package doc_test 2 3 import ( 4 "regexp" 5 "strings" 6 "testing" 7 8 "github.com/google/go-cmp/cmp" 9 "src.elv.sh/pkg/mods/doc" 10 "src.elv.sh/pkg/testutil" 11 "src.elv.sh/pkg/ui" 12 ) 13 14 var Dedent = testutil.Dedent 15 16 var matchAndShowTests = []struct { 17 name string 18 markdown string 19 qs []string 20 want []string 21 }{ 22 { 23 name: "no match", 24 markdown: "Here is some doc", 25 qs: []string{"foo"}, 26 want: nil, 27 }, 28 { 29 name: "not all queries match", 30 markdown: "Here is some doc", 31 qs: []string{"some", "foo"}, 32 want: nil, 33 }, 34 35 { 36 name: "one query matches one block", 37 markdown: "Here is some doc", 38 qs: []string{"some"}, 39 want: []string{"Here is {some} doc"}, 40 }, 41 { 42 name: "multiple queries match one block", 43 markdown: "Here is some doc", 44 qs: []string{"some", "doc"}, 45 want: []string{"Here is {some} {doc}"}, 46 }, 47 { 48 name: "multiple queries match one block, reverse order", 49 markdown: "Here is some doc", 50 qs: []string{"doc", "some"}, 51 want: []string{"Here is {some} {doc}"}, 52 }, 53 { 54 name: "one query matches multiple blocks, only first matched block shown", 55 markdown: Dedent(` 56 Here is some doc 57 58 Here is some more doc 59 `), 60 qs: []string{"some"}, 61 want: []string{"Here is {some} doc"}, 62 }, 63 { 64 name: "multiple queries match multiple blocks respectively", 65 markdown: Dedent(` 66 Here is some doc 67 68 Here is some more doc 69 `), 70 qs: []string{"some", "more"}, 71 want: []string{ 72 "Here is {some} doc", 73 "Here is some {more} doc", 74 }, 75 }, 76 { 77 name: "overlapping matches", 78 markdown: "Here is some doc", 79 qs: []string{"is some", "some doc"}, 80 want: []string{"Here {is some doc}"}, 81 }, 82 83 { 84 name: "match in first sentence", 85 markdown: "Here is some doc. Here is more. Here is even more.", 86 qs: []string{"some"}, 87 want: []string{"Here is {some} doc. …"}, 88 }, 89 { 90 name: "match in last sentence", 91 markdown: "Here is some doc. Here is more. Here is even more.", 92 qs: []string{"even"}, 93 want: []string{"… Here is {even} more."}, 94 }, 95 { 96 name: "match in middle sentence", 97 markdown: "Here is some doc. Here is more. Here is even more.", 98 qs: []string{"is more"}, 99 want: []string{"… Here {is more}. …"}, 100 }, 101 { 102 name: "matches in adjacent sentences", 103 markdown: "Here is some doc. Here is more. Here is even more.", 104 qs: []string{"some", "more"}, 105 want: []string{"Here is {some} doc. Here is {more}. …"}, 106 }, 107 { 108 name: "matches in non-adjacent sentences", 109 markdown: "Here is some doc. Here is more. Here is even more.", 110 qs: []string{"some", "even"}, 111 want: []string{"Here is {some} doc. … Here is {even} more."}, 112 }, 113 { 114 name: "multiple matches in one sentence", 115 markdown: "Here is some doc. Here is more.", 116 qs: []string{"some", "doc"}, 117 want: []string{"Here is {some} {doc}. …"}, 118 }, 119 { 120 name: "one match spanning multiple sentences", 121 markdown: "Here is some doc. Here is more. Here is even more.", 122 qs: []string{"some doc. Here", "even"}, 123 want: []string{"Here is {some doc. Here} is more. Here is {even} more."}, 124 }, 125 126 { 127 name: "match in first line of code block", 128 markdown: codeBlockWithLines("echo foo", "echo bar", "echo lorem"), 129 qs: []string{"foo"}, 130 want: []string{"echo {foo} …"}, 131 }, 132 { 133 name: "match in last line of code block", 134 markdown: codeBlockWithLines("echo foo", "echo bar", "echo lorem"), 135 qs: []string{"lorem"}, 136 want: []string{"… echo {lorem}"}, 137 }, 138 { 139 name: "match in middle line of code block", 140 markdown: codeBlockWithLines("echo foo", "echo bar", "echo lorem"), 141 qs: []string{"bar"}, 142 want: []string{"… echo {bar} …"}, 143 }, 144 { 145 name: "matches in adjacent lines", 146 markdown: codeBlockWithLines("echo foo", "echo bar", "echo lorem"), 147 qs: []string{"foo", "bar"}, 148 want: []string{"echo {foo} … echo {bar} …"}, 149 }, 150 { 151 name: "matches in non-adjacent lines", 152 markdown: codeBlockWithLines("echo foo", "echo bar", "echo lorem"), 153 qs: []string{"foo", "lorem"}, 154 want: []string{"echo {foo} … echo {lorem}"}, 155 }, 156 { 157 name: "multiple matches in one line", 158 markdown: codeBlockWithLines("echo foo", "echo bar", "echo lorem"), 159 qs: []string{"ch", "fo"}, 160 want: []string{"e{ch}o {fo}o …"}, 161 }, 162 { 163 name: "one match spanning multiple lines", 164 markdown: codeBlockWithLines("echo foo", "echo bar", "echo lorem"), 165 qs: []string{"foo\necho"}, 166 want: []string{"echo {foo … echo} bar …"}, 167 }, 168 } 169 170 func codeBlockWithLines(lines ...string) string { 171 return "```\n" + strings.Join(lines, "\n") + "\n```" 172 } 173 174 // Test match and matchedBlock.Show together. They are used together in actual 175 // production code and easier to test together. 176 func TestMatchAndShow(t *testing.T) { 177 for _, tc := range matchAndShowTests { 178 t.Run(tc.name, func(t *testing.T) { 179 want := tc.want 180 for i := range want { 181 want[i] = highlightBraced(want[i]) 182 } 183 got := matchAndShow(tc.markdown, tc.qs) 184 if diff := cmp.Diff(want, got); diff != "" { 185 t.Errorf("unexpected result (-want +got):\n%s", diff) 186 } 187 }) 188 } 189 } 190 191 func matchAndShow(markdown string, qs []string) []string { 192 bs, ok := doc.Match(markdown, qs) 193 if !ok { 194 return nil 195 } 196 shown := make([]string, len(bs)) 197 for i, b := range bs { 198 shown[i] = b.Show() 199 } 200 return shown 201 } 202 203 var braced = regexp.MustCompile(`\{.*?\}`) 204 205 func highlightBraced(s string) string { 206 return braced.ReplaceAllStringFunc(s, func(p string) string { 207 return ui.T(p[1:len(p)-1], ui.Bold, ui.FgRed).VTString() 208 }) 209 }