]> git.giacomolli.uk - onechat/blob - telegram_markdown_test.go
Back up the daemon and restore its data
[onechat] / telegram_markdown_test.go
1 package main
2
3 import (
4         "testing"
5
6         "github.com/stretchr/testify/require"
7 )
8
9 func TestMarkdownEntities(t *testing.T) {
10         testCases := []struct {
11                 name     string
12                 markdown string
13                 text     string
14                 entities []TelegramEntity
15         }{
16                 {
17                         name:     "double asterisks give bold",
18                         markdown: "a **b** c",
19                         text:     "a b c",
20                         entities: []TelegramEntity{
21                                 {
22                                         Type:   "bold",
23                                         Offset: 2,
24                                         Length: 1,
25                                 },
26                         },
27                 },
28                 {
29                         name:     "double underscores give bold",
30                         markdown: "__bold__",
31                         text:     "bold",
32                         entities: []TelegramEntity{
33                                 {
34                                         Type:   "bold",
35                                         Offset: 0,
36                                         Length: 4,
37                                 },
38                         },
39                 },
40                 {
41                         name:     "single asterisk gives italic",
42                         markdown: "an *odd* word",
43                         text:     "an odd word",
44                         entities: []TelegramEntity{
45                                 {
46                                         Type:   "italic",
47                                         Offset: 3,
48                                         Length: 3,
49                                 },
50                         },
51                 },
52                 {
53                         name:     "single underscore gives italic",
54                         markdown: "an _odd_ word",
55                         text:     "an odd word",
56                         entities: []TelegramEntity{
57                                 {
58                                         Type:   "italic",
59                                         Offset: 3,
60                                         Length: 3,
61                                 },
62                         },
63                 },
64                 {
65                         name:     "double tildes give strikethrough",
66                         markdown: "~~old~~ new",
67                         text:     "old new",
68                         entities: []TelegramEntity{
69                                 {
70                                         Type:   "strikethrough",
71                                         Offset: 0,
72                                         Length: 3,
73                                 },
74                         },
75                 },
76                 {
77                         name:     "backticks give inline code with no entity inside",
78                         markdown: "run `go **test**` now",
79                         text:     "run go **test** now",
80                         entities: []TelegramEntity{
81                                 {
82                                         Type:   "code",
83                                         Offset: 4,
84                                         Length: 11,
85                                 },
86                         },
87                 },
88                 {
89                         name:     "double backticks hold a backtick",
90                         markdown: "``a ` b``",
91                         text:     "a ` b",
92                         entities: []TelegramEntity{
93                                 {
94                                         Type:   "code",
95                                         Offset: 0,
96                                         Length: 5,
97                                 },
98                         },
99                 },
100                 {
101                         name:     "link gives a text link",
102                         markdown: "see [the docs](https://example.com/a_b) here",
103                         text:     "see the docs here",
104                         entities: []TelegramEntity{
105                                 {
106                                         Type:   "text_link",
107                                         Offset: 4,
108                                         Length: 8,
109                                         URL:    "https://example.com/a_b",
110                                 },
111                         },
112                 },
113                 {
114                         name:     "bold inside a link nests",
115                         markdown: "[a **b** c](https://example.com)",
116                         text:     "a b c",
117                         entities: []TelegramEntity{
118                                 {
119                                         Type:   "text_link",
120                                         Offset: 0,
121                                         Length: 5,
122                                         URL:    "https://example.com",
123                                 },
124                                 {
125                                         Type:   "bold",
126                                         Offset: 2,
127                                         Length: 1,
128                                 },
129                         },
130                 },
131                 {
132                         name:     "code block with a language gives pre with the language",
133                         markdown: "Commit:\n```text\nFix the **bug**\n\nBody\n```\nDone.",
134                         text:     "Commit:\nFix the **bug**\n\nBody\nDone.",
135                         entities: []TelegramEntity{
136                                 {
137                                         Type:     "pre",
138                                         Offset:   8,
139                                         Length:   21,
140                                         Language: "text",
141                                 },
142                         },
143                 },
144                 {
145                         name:     "code block without a language gives pre",
146                         markdown: "```\nls -l\n```",
147                         text:     "ls -l",
148                         entities: []TelegramEntity{
149                                 {
150                                         Type:   "pre",
151                                         Offset: 0,
152                                         Length: 5,
153                                 },
154                         },
155                 },
156                 {
157                         name:     "heading becomes bold with its inline marks",
158                         markdown: "## The `plan`\nnext",
159                         text:     "The plan\nnext",
160                         entities: []TelegramEntity{
161                                 {
162                                         Type:   "bold",
163                                         Offset: 0,
164                                         Length: 8,
165                                 },
166                                 {
167                                         Type:   "code",
168                                         Offset: 4,
169                                         Length: 4,
170                                 },
171                         },
172                 },
173                 {
174                         name:     "list, quote and table stay as text",
175                         markdown: "- one\n* two\n1. three\n> quote\n| a | b |\n|---|---|",
176                         text:     "- one\n* two\n1. three\n> quote\n| a | b |\n|---|---|",
177                 },
178                 {
179                         name:     "asterisk of a list item with italic later stays",
180                         markdown: "* item with *stress*",
181                         text:     "* item with stress",
182                         entities: []TelegramEntity{
183                                 {
184                                         Type:   "italic",
185                                         Offset: 12,
186                                         Length: 6,
187                                 },
188                         },
189                 },
190                 {
191                         name:     "unclosed marks stay as text",
192                         markdown: "**open, `tick, [link](, ~~gone and *star",
193                         text:     "**open, `tick, [link](, ~~gone and *star",
194                 },
195                 {
196                         name:     "unclosed code fence stays as text",
197                         markdown: "```go\nfmt.Println()",
198                         text:     "```go\nfmt.Println()",
199                 },
200                 {
201                         name:     "snake case words stay as text",
202                         markdown: "set snake_case_words and max_tokens_count",
203                         text:     "set snake_case_words and max_tokens_count",
204                 },
205                 {
206                         name:     "multiplication stays as text",
207                         markdown: "2 * 3 * 4",
208                         text:     "2 * 3 * 4",
209                 },
210                 {
211                         name:     "mark does not cross a line break",
212                         markdown: "**a\nb**",
213                         text:     "**a\nb**",
214                 },
215                 {
216                         name:     "backslash makes a mark plain",
217                         markdown: `\*not italic\* and C:\Users`,
218                         text:     `*not italic* and C:\Users`,
219                 },
220                 {
221                         name:     "character outside the BMP moves the offset by two",
222                         markdown: "\U0001F600 **b**",
223                         text:     "\U0001F600 b",
224                         entities: []TelegramEntity{
225                                 {
226                                         Type:   "bold",
227                                         Offset: 3,
228                                         Length: 1,
229                                 },
230                         },
231                 },
232         }
233
234         for _, tc := range testCases {
235                 t.Run(tc.name, func(t *testing.T) {
236                         text, entities := telegramMarkdownEntities(tc.markdown)
237                         require.Equal(t, tc.text, text)
238                         require.Equal(t, tc.entities, entities)
239                 })
240         }
241 }
242
243 func TestEscapeTags(t *testing.T) {
244         testCases := []struct {
245                 name     string
246                 markdown string
247                 escaped  string
248         }{
249                 {
250                         name:     "tag in prose shows as text",
251                         markdown: "Use a <details> tag for the rest.",
252                         escaped:  "Use a &lt;details> tag for the rest.",
253                 },
254                 {
255                         name:     "tag in inline code stays as written",
256                         markdown: "Use `<details>` and `` a<b && c ``, not <b>.",
257                         escaped:  "Use `<details>` and `` a<b && c ``, not &lt;b>.",
258                 },
259                 {
260                         name:     "tag in a code block stays as written",
261                         markdown: "<p>\n\n```html\n<details>&amp;\n```\n\n<p>",
262                         escaped:  "&lt;p>\n\n```html\n<details>&amp;\n```\n\n&lt;p>",
263                 },
264                 {
265                         name:     "code block that does not close stays as written",
266                         markdown: "a <b>\n```\n<details>",
267                         escaped:  "a &lt;b>\n```\n<details>",
268                 },
269                 {
270                         name:     "tag in a table cell shows as text",
271                         markdown: "| Tag | Use |\n|-----|-----|\n| <br> | `<br>` |",
272                         escaped:  "| Tag | Use |\n|-----|-----|\n| &lt;br> | `<br>` |",
273                 },
274                 {
275                         name:     "autolink shows as text",
276                         markdown: "See <https://example.com>.",
277                         escaped:  "See &lt;https://example.com>.",
278                 },
279                 {
280                         name:     "entity in prose shows as written",
281                         markdown: "Write &lt; or &amp; for R&D.",
282                         escaped:  "Write &amp;lt; or &amp;amp; for R&amp;D.",
283                 },
284                 {
285                         name:     "backslash before a bracket gets no special case",
286                         markdown: `a \<b> and \&c`,
287                         escaped:  `a \&lt;b> and \&amp;c`,
288                 },
289                 {
290                         name:     "backtick after a backslash opens no code",
291                         markdown: "a \\`<b>\\` c",
292                         escaped:  "a \\`&lt;b>\\` c",
293                 },
294                 {
295                         name:     "backtick run that opens no code stays as text",
296                         markdown: "a ``b` <c>",
297                         escaped:  "a ``b` &lt;c>",
298                 },
299                 {
300                         name:     "dollar, pipe, and equals signs stay as written",
301                         markdown: "$5 or $10, a || b, ==c==",
302                         escaped:  "$5 or $10, a || b, ==c==",
303                 },
304         }
305
306         for _, tc := range testCases {
307                 t.Run(tc.name, func(t *testing.T) {
308                         require.Equal(t, tc.escaped, telegramEscapeTags(tc.markdown))
309                         require.Equal(t, tc.markdown, telegramUnescapeTags(tc.escaped))
310                 })
311         }
312 }