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  }