github.com/tada-team/tdproto@v1.51.57/tdmarkup/markup_scanner_test.go (about)

     1  package tdmarkup
     2  
     3  import (
     4  	"regexp"
     5  	"testing"
     6  )
     7  
     8  func TestToPlainNoQuotes(t *testing.T) {
     9  	for k, v := range map[string]struct {
    10  		raw   string
    11  		plain string
    12  	}{
    13  		"noop": {
    14  			raw:   "123",
    15  			plain: "123",
    16  		},
    17  		"quote": {
    18  			raw:   "> 123\n456",
    19  			plain: "456",
    20  		},
    21  	} {
    22  		t.Run(k, func(t *testing.T) {
    23  			s, entities := ParseString(v.raw, nil)
    24  			if s != v.raw {
    25  				t.Fatalf("invalid ParseString text.\n got: '%s'\nwant: '%s'", s, v.raw)
    26  			}
    27  			if text := ToPlain(s, entities, &ToPlainOpts{
    28  				DisableQuotes: true,
    29  			}); text != v.plain {
    30  				t.Errorf(
    31  					"invalid ToPlainNoQuotes() output\n raw: '%s'\n got: '%s'\nwant: '%s'\n ent: %+v",
    32  					v.raw, text, v.plain, entities,
    33  				)
    34  			}
    35  		})
    36  	}
    37  }
    38  
    39  func TestParse(t *testing.T) {
    40  	for _, v := range MarkupTestCases {
    41  		t.Run(v.Title, func(t *testing.T) {
    42  			s, entities := ParseString(v.Raw, v.Links)
    43  			if s != v.Raw {
    44  				t.Fatalf("invalid ParseString text.\n got: '%s'\nwant: '%s'", s, v.Raw)
    45  			}
    46  
    47  			if v.Html != "" {
    48  				if text := ToHtml(s, entities); text != v.Html {
    49  					t.Errorf(
    50  						"invalid ToHtml() output\n raw: '%s'\n got: '%s'\nwant: '%s'\n ent: %+v",
    51  						v.Raw, text, v.Html, entities,
    52  					)
    53  				}
    54  			}
    55  
    56  			if v.Plain != "" {
    57  				if text := ToPlain(s, entities, nil); text != v.Plain {
    58  					t.Errorf(
    59  						"invalid ToPlain() output\n raw: '%s'\n got: '%s'\nwant: '%s'\n ent: %+v",
    60  						v.Raw, text, v.Plain, entities,
    61  					)
    62  				}
    63  			}
    64  		})
    65  	}
    66  }
    67  
    68  func TestMustTime(t *testing.T) {
    69  	mustTime("2020-10-27T12:24:09.781121Z")
    70  	mustTime("2000-01-02T17:15:00.000000Z")
    71  	mustTime("2006-01-02T15:04:05.000000-0700")
    72  }
    73  
    74  func TestContainsTime(t *testing.T) {
    75  	for k, v := range map[string]struct {
    76  		text     string
    77  		contains bool
    78  	}{
    79  		"base format": {
    80  			text:     "<2020-10-27T12:24:09.781121Z>",
    81  			contains: true,
    82  		},
    83  		"tada format": {
    84  			text:     "<2020-10-02T15:04:05.000000-0700>",
    85  			contains: true,
    86  		},
    87  		"into chars": {
    88  			text:     "*<2000-01-02T17:15:00.000000Z>*",
    89  			contains: true,
    90  		},
    91  		"simple string": {
    92  			text:     "asdasdasdasd",
    93  			contains: false,
    94  		},
    95  		"simple string with quotes": {
    96  			text:     "<asdasdasdasd>",
    97  			contains: false,
    98  		},
    99  		"between words": {
   100  			text:     "hello <2020-10-02T15:04:05.000000-0700> world",
   101  			contains: true,
   102  		},
   103  	} {
   104  		t.Run(k, func(t *testing.T) {
   105  			if contains := ContainsTime(v.text); contains != v.contains {
   106  				t.Error("bad ContainsTime result. want:", v.contains, "got:", contains, "text:", v.text)
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  // BenchmarkParse/regex-12                 	  107926	     11367 ns/op	    1129 B/op	      34 allocs/op
   113  //
   114  // BenchmarkParse/markupScanner-12         	  238516	      4882 ns/op	    2600 B/op	      71 allocs/op
   115  // => strings.Builder.Grow
   116  // BenchmarkParse/markupScanner-12         	  323514	      3734 ns/op	    2584 B/op	      68 allocs/op
   117  func BenchmarkParse(b *testing.B) {
   118  	raw := "*bold* /italic/ 1234567 _3_ `code`"
   119  	plain := "bold italic 1234567 3 code"
   120  
   121  	b.Run("markupScanner", func(b *testing.B) {
   122  		b.ReportAllocs()
   123  		for i := 0; i < b.N; i++ {
   124  			s, entities := ParseString(raw, nil)
   125  			res := ToPlain(s, entities, nil)
   126  			if res != plain {
   127  				b.Fatalf("invalid plain, got: %s, want: %s", res, plain)
   128  			}
   129  		}
   130  	})
   131  
   132  	b.Run("regex", func(b *testing.B) {
   133  		b.ReportAllocs()
   134  		for i := 0; i < b.N; i++ {
   135  			res := clearFormat(raw)
   136  			if res != plain {
   137  				b.Fatalf("invalid plain, got: %s, want: %s", res, plain)
   138  			}
   139  		}
   140  	})
   141  }
   142  
   143  // BenchmarkNoop-12    	  502996	      2363 ns/op	     432 B/op	      57 allocs/op
   144  // =>
   145  // BenchmarkNoop-12    	 2903997	       442.5 ns/op	     192 B/op	       4 allocs/op
   146  func BenchmarkNoop(b *testing.B) {
   147  	b.ReportAllocs()
   148  
   149  	raw := "bold italic 1234567 3 code"
   150  	plain := "bold italic 1234567 3 code"
   151  
   152  	for i := 0; i < b.N; i++ {
   153  		s, entities := ParseString(raw, nil)
   154  		res := ToPlain(s, entities, nil)
   155  		if res != plain {
   156  			b.Fatalf("invalid plain, got: %s, want: %s", res, plain)
   157  		}
   158  	}
   159  }
   160  
   161  func mask(s string) *regexp.Regexp {
   162  	return regexp.MustCompile(`(^|\s)` + s + `([^\s` + s + `].*?[^\s` + s + `]|[^\s` + s + `])` + s + `(\s|$|\?|:|\.|,|!)`)
   163  }
   164  
   165  var formatRules = []*regexp.Regexp{
   166  	regexp.MustCompile("(?ms)(^|\\s)```(.+?)```" + `(\s|$|\?|:|\.|,|!)`),
   167  	mask("`"),
   168  	mask(`\*`),
   169  	mask("/"),
   170  	mask("_"),
   171  	mask("~"),
   172  }
   173  
   174  func clearFormat(text string) string {
   175  	for _, regex := range formatRules {
   176  		text = regex.ReplaceAllStringFunc(text, func(m string) string {
   177  			parts := regex.FindStringSubmatch(m)
   178  			return parts[1] + parts[2] + parts[3]
   179  		})
   180  	}
   181  	return text
   182  }