github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/parser_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  	"testing"
     8  
     9  	c "github.com/Azareal/Gosora/common"
    10  )
    11  
    12  func TestPreparser(t *testing.T) {
    13  	miscinit(t)
    14  	if !c.PluginsInited {
    15  		c.InitPlugins()
    16  	}
    17  	l := &METriList{nil}
    18  
    19  	// Note: The open tag is evaluated without knowledge of the close tag for efficiency and simplicity, so the parser autofills the associated close tag when it finds an open tag without a partner
    20  	l.Add("", "")
    21  	l.Add(" ", "")
    22  	l.Add(" hi", "hi")
    23  	l.Add("hi ", "hi")
    24  	l.Add("hi", "hi")
    25  	l.Add(":grinning:", "πŸ˜€")
    26  	l.Add(":grinning: :grinning:", "πŸ˜€ πŸ˜€")
    27  	l.Add(" :grinning: ", "πŸ˜€")
    28  	l.Add(": :grinning: :", ": πŸ˜€ :")
    29  	l.Add("::grinning::", ":πŸ˜€:")
    30  	//l.Add("d:grinning:d", "d:grinning:d") // todo
    31  	l.Add("d :grinning: d", "d πŸ˜€ d")
    32  	l.Add("πŸ˜€", "πŸ˜€")
    33  	l.Add(" ", "")
    34  	l.Add("<p>", "")
    35  	l.Add("</p>", "")
    36  	l.Add("<p></p>", "")
    37  
    38  	l.Add("<", "&lt;")
    39  	l.Add(">", "&gt;")
    40  	l.Add("<meow>", "&lt;meow&gt;")
    41  	l.Add("&lt;", "&amp;lt;")
    42  	l.Add("&", "&amp;")
    43  
    44  	// Note: strings.TrimSpace strips newlines, if there's nothing before or after them
    45  	l.Add("<br>", "")
    46  	l.Add("<br />", "")
    47  	l.Add("\\n", "\n", "")
    48  	l.Add("\\n\\n", "\n\n", "")
    49  	l.Add("\\n\\n\\n", "\n\n\n", "")
    50  	l.Add("\\r\\n", "\r\n", "") // Windows style line ending
    51  	l.Add("\\n\\r", "\n\r", "")
    52  
    53  	l.Add("ho<br>ho", "ho\n\nho")
    54  	l.Add("ho<br />ho", "ho\n\nho")
    55  	l.Add("ho\\nho", "ho\nho", "ho\nho")
    56  	l.Add("ho\\n\\nho", "ho\n\nho", "ho\n\nho")
    57  	//l.Add("ho\\n\\n\\n\\nho", "ho\n\n\n\nho", "ho\n\n\nho")
    58  	l.Add("ho\\r\\nho", "ho\r\nho", "ho\nho") // Windows style line ending
    59  	l.Add("ho\\n\\rho", "ho\n\rho", "ho\nho")
    60  
    61  	l.Add("<b></b>", "<strong></strong>")
    62  	l.Add("<b>hi</b>", "<strong>hi</strong>")
    63  	l.Add("<b>h</b>", "<strong>h</strong>")
    64  	l.Add("<s>hi</s>", "<del>hi</del>")
    65  	l.Add("<del>hi</del>", "<del>hi</del>")
    66  	l.Add("<u>hi</u>", "<u>hi</u>")
    67  	l.Add("<em>hi</em>", "<em>hi</em>")
    68  	l.Add("<i>hi</i>", "<em>hi</em>")
    69  	l.Add("<strong>hi</strong>", "<strong>hi</strong>")
    70  	l.Add("<spoiler>hi</spoiler>", "<spoiler>hi</spoiler>")
    71  	l.Add("<g>hi</g>", "hi") // Grammarly fix
    72  	l.Add("<b><i>hi</i></b>", "<strong><em>hi</em></strong>")
    73  	l.Add("<strong><em>hi</em></strong>", "<strong><em>hi</em></strong>")
    74  	l.Add("<b><i><b>hi</b></i></b>", "<strong><em><strong>hi</strong></em></strong>")
    75  	l.Add("<strong><em><strong>hi</strong></em></strong>", "<strong><em><strong>hi</strong></em></strong>")
    76  	l.Add("<div>hi</div>", "&lt;div&gt;hi&lt;/div&gt;")
    77  	l.Add("<span>hi</span>", "hi") // This is stripped since the editor (Trumbowyg) likes blasting useless spans
    78  	l.Add("<span   >hi</span>", "hi")
    79  	l.Add("<span style='background-color: yellow;'>hi</span>", "hi")
    80  	l.Add("<span style='background-color: yellow;'>>hi</span>", "&gt;hi")
    81  	l.Add("<b>hi", "<strong>hi</strong>")
    82  	l.Add("hi</b>", "hi&lt;/b&gt;")
    83  	l.Add("</b>", "&lt;/b&gt;")
    84  	l.Add("</del>", "&lt;/del&gt;")
    85  	l.Add("</strong>", "&lt;/strong&gt;")
    86  	l.Add("<b>", "<strong></strong>")
    87  	l.Add("<span style='background-color: yellow;'>hi", "hi")
    88  	l.Add("<span style='background-color:yellow;'>hi", "hi")
    89  	l.Add("hi</span>", "hi")
    90  	l.Add("</span>", "")
    91  	l.Add("<span></span>", "")
    92  	l.Add("<span   ></span>", "")
    93  	l.Add("<span><span></span></span>", "")
    94  	l.Add("<span><b></b></span>", "<strong></strong>")
    95  	l.Add("<h1>t</h1>", "<h2>t</h2>")
    96  	l.Add("<h2>t</h2>", "<h3>t</h3>")
    97  	l.Add("<h3>t</h3>", "<h4>t</h4>")
    98  	l.Add("<></>", "&lt;&gt;&lt;/&gt;")
    99  	l.Add("</><>", "&lt;/&gt;&lt;&gt;")
   100  	l.Add("<>", "&lt;&gt;")
   101  	l.Add("</>", "&lt;/&gt;")
   102  	l.Add("<p>hi</p>", "hi")
   103  	l.Add("<p></p>", "")
   104  	l.Add("<blockquote>hi</blockquote>", "<blockquote>hi</blockquote>")
   105  	l.Add("<blockquote><b>hi</b></blockquote>", "<blockquote><strong>hi</strong></blockquote>")
   106  	l.Add("<blockquote><meow>hi</meow></blockquote>", "<blockquote>&lt;meow&gt;hi&lt;/meow&gt;</blockquote>")
   107  	l.Add("\\<blockquote>hi</blockquote>", "&lt;blockquote&gt;hi&lt;/blockquote&gt;")
   108  	//l.Add("\\\\<blockquote><meow>hi</meow></blockquote>", "\\<blockquote>&lt;meow&gt;hi&lt;/meow&gt;</blockquote>") // TODO: Double escapes should print a literal backslash
   109  	//l.Add("&lt;blockquote&gt;hi&lt;/blockquote&gt;", "&lt;blockquote&gt;hi&lt;/blockquote&gt;") // TODO: Stop double-entitising this
   110  	l.Add("\\<blockquote>hi</blockquote>\\<blockquote>hi</blockquote>", "&lt;blockquote&gt;hi&lt;/blockquote&gt;&lt;blockquote&gt;hi&lt;/blockquote&gt;")
   111  	l.Add("\\<a itemprop=\"author\">Admin</a>", "&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;")
   112  	l.Add("<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>", "<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>")
   113  	l.Add("\n<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>\n", "<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>")
   114  	l.Add("tt\n<blockquote>\\<a itemprop=\"author\">Admin</a></blockquote>\ntt", "tt\n<blockquote>&lt;a itemprop=&#34;author&#34;&gt;Admin&lt;/a&gt;</blockquote>\ntt")
   115  	l.Add("@", "@")
   116  	l.Add("@Admin", "@1")
   117  	l.Add("@Bah", "@Bah")
   118  	l.Add(" @Admin", "@1")
   119  	l.Add("\n@Admin", "@1")
   120  	l.Add("@Admin\n", "@1")
   121  	l.Add("@Admin\ndd", "@1\ndd")
   122  	l.Add("d@Admin", "d@Admin")
   123  	l.Add("\\@Admin", "@Admin")
   124  	l.Add("@ε…ƒζ°—", "@ε…ƒζ°—")
   125  	// TODO: More tests for unicode names?
   126  	//l.Add("\\\\@Admin", "@1")
   127  	//l.Add("byte 0", string([]byte{0}), "")
   128  	l.Add("byte 'a'", string([]byte{'a'}), "a")
   129  	//l.Add("byte 255", string([]byte{255}), "")
   130  	//l.Add("rune 0", string([]rune{0}), "")
   131  	// TODO: Do a test with invalid UTF-8 input
   132  
   133  	for _, item := range l.Items {
   134  		if res := c.PreparseMessage(item.Msg); res != item.Expects {
   135  			if item.Name != "" {
   136  				t.Error("Name: ", item.Name)
   137  			}
   138  			t.Error("Testing string '" + item.Msg + "'")
   139  			t.Error("Bad output:", "'"+res+"'")
   140  			//t.Error("Ouput in bytes:", []byte(res))
   141  			t.Error("Expected:", "'"+item.Expects+"'")
   142  		}
   143  	}
   144  }
   145  
   146  func TestParser(t *testing.T) {
   147  	miscinit(t)
   148  	if !c.PluginsInited {
   149  		c.InitPlugins()
   150  	}
   151  	l := &METriList{nil}
   152  
   153  	url := "github.com/Azareal/Gosora"
   154  	eurl := "<a rel='ugc'href='//" + url + "'>" + url + "</a>"
   155  	l.Add("", "")
   156  	l.Add("haha", "haha")
   157  	l.Add(":P", "πŸ˜›")
   158  	l.Add(" :P ", " πŸ˜› ")
   159  	l.Add(":p", "πŸ˜›")
   160  	l.Add("d:p", "d:p")
   161  	l.Add(":pd", "πŸ˜›d")
   162  	l.Add(":pdd", "πŸ˜›dd")
   163  	l.Add(":pddd", "πŸ˜›ddd")
   164  	l.Add(":p d", "πŸ˜› d")
   165  	l.Add(":p dd", "πŸ˜› dd")
   166  	l.Add(":p ddd", "πŸ˜› ddd")
   167  	//l.Add(":p:p:p", "πŸ˜›πŸ˜›πŸ˜›")
   168  	l.Add(":p:p:p", "πŸ˜›:p:p")
   169  	l.Add(":p :p", "πŸ˜› πŸ˜›")
   170  	l.Add(":p :p :p", "πŸ˜› πŸ˜› πŸ˜›")
   171  	l.Add(":p :p :p :p", "πŸ˜› πŸ˜› πŸ˜› πŸ˜›")
   172  	l.Add(":p  :p  :p", "πŸ˜›  πŸ˜›  πŸ˜›")
   173  	l.Add("word:p", "word:p")
   174  	l.Add("word:pword", "word:pword")
   175  	l.Add(":pword", "πŸ˜›word") // TODO: Change the semantics on this to detect the succeeding character?
   176  	l.Add("word :p", "word πŸ˜›")
   177  	l.Add(":p word", "πŸ˜› word")
   178  	l.Add("<b>t</b>", "<b>t</b>")
   179  	l.Add("//", "//")
   180  	l.Add("http://", "<red>[Invalid URL]</red>")
   181  	//l.Add("https://", "<red>[Invalid URL]</red>")
   182  	l.Add("ipfs://", "<red>[Invalid URL]</red>")
   183  	l.Add("ftp://", "<red>[Invalid URL]</red>")
   184  	l.Add("git://", "<red>[Invalid URL]</red>")
   185  	l.Add("ssh://", "ssh://")
   186  	l.Add("fff://", "fff://")
   187  
   188  	l.Add("// ", "// ")
   189  	l.Add("// //", "// //")
   190  	l.Add("// // //", "// // //")
   191  	l.Add("http:// ", "<red>[Invalid URL]</red> ")
   192  	l.Add("https:// ", "<red>[Invalid URL]</red> ")
   193  	l.Add("ftp:// ", "<red>[Invalid URL]</red> ")
   194  	l.Add("git:// ", "<red>[Invalid URL]</red> ")
   195  	l.Add("ssh:// ", "ssh:// ")
   196  	l.Add("fff:// ", "fff:// ")
   197  
   198  	l.Add("//t", "<a rel='ugc'href='//t'>t</a>")
   199  	l.Add("// t", "// t")
   200  	l.Add("http:// t", "<red>[Invalid URL]</red> t")
   201  
   202  	l.Add("g", "g")
   203  	l.Add("g/", "g/")
   204  	l.Add("g//", "g//")
   205  	l.Add("/g", "/g")
   206  	l.Add("/gg", "/gg")
   207  	l.Add("/g/", "/g/")
   208  	l.Add("hi", "hi")
   209  	l.Add("hit", "hit")
   210  	l.Add("hit:", "hit:")
   211  	l.Add("hit:/", "hit:/")
   212  	l.Add("hit://", "hit://")
   213  	l.Add("hit://t", "hit://t")
   214  	l.Add("h", "h")
   215  	l.Add("ht", "ht")
   216  	l.Add("htt", "htt")
   217  	l.Add("http", "http")
   218  	l.Add("http:", "http:")
   219  	//t l.Add("http:/", "http:/")
   220  	//t l.Add("http:/d", "http:/d")
   221  	l.Add("http:d", "http:d")
   222  	l.Add("https:", "https:")
   223  	l.Add("gttps:", "gttps:")
   224  	l.Add("gttps:/", "gttps:/")
   225  	l.Add("gttps://", "gttps://")
   226  	l.Add("ftp:", "ftp:")
   227  	l.Add("git:", "git:")
   228  	l.Add("ssh:", "ssh:")
   229  
   230  	l.Add("http", "http")
   231  	l.Add("https", "https")
   232  	l.Add("ftp", "ftp")
   233  	l.Add("git", "git")
   234  	l.Add("ssh", "ssh")
   235  
   236  	l.Add("ht", "ht")
   237  	l.Add("htt", "htt")
   238  	l.Add("ft", "ft")
   239  	l.Add("gi", "gi")
   240  	l.Add("ss", "ss")
   241  	l.Add("haha\nhaha\nhaha", "haha<br>haha<br>haha")
   242  	l.Add("//"+url, eurl)
   243  	l.Add("//a", "<a rel='ugc'href='//a'>a</a>")
   244  	l.Add(" //a", " <a rel='ugc'href='//a'>a</a>")
   245  	l.Add("//a ", "<a rel='ugc'href='//a'>a</a> ")
   246  	l.Add(" //a ", " <a rel='ugc'href='//a'>a</a> ")
   247  	l.Add("d //a ", "d <a rel='ugc'href='//a'>a</a> ")
   248  	l.Add("ddd ddd //a ", "ddd ddd <a rel='ugc'href='//a'>a</a> ")
   249  	l.Add("https://"+url, "<a rel='ugc'href='https://"+url+"'>"+url+"</a>")
   250  	l.Add("https://t", "<a rel='ugc'href='https://t'>t</a>")
   251  	l.Add("https://en.wikipedia.org/wiki/First_they_came_...", "<a rel='ugc'href='https://en.wikipedia.org/wiki/First_they_came_...'>en.wikipedia.org/wiki/First_they_came_...</a>") // this frequently fails in some chat clients, we should make sure that doesn't happen here
   252  	l.Add("http://"+url, "<a rel='ugc'href='http://"+url+"'>"+url+"</a>")
   253  	l.Add("#http://"+url, "#http://"+url)
   254  	l.Add("@http://"+url, "<red>[Invalid Profile]</red>ttp://"+url)
   255  	l.Add("//"+url+"\n", "<a rel='ugc'href='//"+url+"'>"+url+"</a><br>")
   256  	l.Add("\n//"+url, "<br>"+eurl)
   257  	l.Add("\n//"+url+"\n", "<br>"+eurl+"<br>")
   258  	l.Add("\n//"+url+"\n\n", "<br>"+eurl+"<br><br>")
   259  	l.Add("//"+url+"\n//"+url, eurl+"<br>"+eurl)
   260  	l.Add("//"+url+" //"+url, eurl+" "+eurl)
   261  	l.Add("//"+url+"  //"+url, eurl+"  "+eurl)
   262  	//l.Add("//"+url+"//"+url, eurl+""+eurl)
   263  	//l.Add("//"+url+"|//"+url, eurl+"|"+eurl)
   264  	l.Add("//"+url+"|//"+url, "<red>[Invalid URL]</red>|//"+url)
   265  	l.Add("//"+url+"//"+url, "<a rel='ugc'href='//"+url+"//"+url+"'>"+url+"//"+url+"</a>")
   266  	l.Add("//"+url+"\n\n//"+url, eurl+"<br><br>"+eurl)
   267  
   268  	pre2 := c.Config.SslSchema
   269  	c.Config.SslSchema = true
   270  	local := func(u string) {
   271  		s := "//" + c.Site.URL
   272  		fs := "http://" + c.Site.URL
   273  		ipns := "ipns://" + c.Site.URL
   274  		if c.Config.SslSchema {
   275  			s = "https:" + s
   276  			fs = "https://" + c.Site.URL
   277  		}
   278  		l.Add("//"+u, "<a href='"+fs+"'>"+c.Site.URL+"</a>")
   279  
   280  		// TODO: Strip redundant slashes?
   281  		l.Add("//"+u+"/", "<a href='"+fs+"/'>"+c.Site.URL+"/</a>")
   282  		l.Add("//"+u+"//", "<a href='"+fs+"//'>"+c.Site.URL+"//</a>")
   283  
   284  		l.Add("//"+u+"\n", "<a href='"+fs+"'>"+c.Site.URL+"</a><br>")
   285  		l.Add("//"+u+"\n//"+u, "<a href='"+fs+"'>"+c.Site.URL+"</a><br><a href='"+fs+"'>"+c.Site.URL+"</a>")
   286  		l.Add("http://"+u, "<a href='"+fs+"'>"+c.Site.URL+"</a>")
   287  		l.Add("https://"+u, "<a href='"+fs+"'>"+c.Site.URL+"</a>")
   288  		l.Add("ipfs://testthis", "<a rel='ugc'href='ipfs://testthis'>ipfs://testthis</a>")
   289  		l.Add(ipns, "<a rel='ugc'href='"+ipns+"'>"+c.Site.URL+"</a>")
   290  
   291  		l.Add("//"+u+"/attachs/sha256hash.webm?sid=1&stype=forums", "<video controls src=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"download>Attachment</a></video>")
   292  		l.Add("//"+u+"/attachs/sha256hash.webm", "<video controls src=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"download>Attachment</a></video>")
   293  		l.Add("//"+u+"/attachs/sha256hash.webm?sid=1", "<video controls src=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"download>Attachment</a></video>")
   294  		l.Add("//"+u+"/attachs/sha256hash.webm?stype=forums", "<video controls src=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.webm?sid=1&amp;stype=forums\"download>Attachment</a></video>")
   295  
   296  		l.Add("//"+u+"/attachs/sha256hash.mp3?sid=1&stype=forums", "<audio controls src=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"download>Attachment</a></audio>")
   297  		l.Add("//"+u+"/attachs/sha256hash.mp3", "<audio controls src=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"download>Attachment</a></audio>")
   298  		l.Add("//"+u+"/attachs/sha256hash.mp3?sid=1", "<audio controls src=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"download>Attachment</a></audio>")
   299  		l.Add("//"+u+"/attachs/sha256hash.mp3?stype=forums", "<audio controls src=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"><a class='attach'href=\""+fs+"/attachs/sha256hash.mp3?sid=1&amp;stype=forums\"download>Attachment</a></audio>")
   300  
   301  		l.Add("//"+u+"/attachs/sha256hash.png?sid=1&stype=forums", "<a href=\""+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums\"><img src='"+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums'class='postImage'></a>")
   302  		l.Add("//"+u+"/attachs/sha256hash?sid=1&stype=forums", "<red>[Invalid URL]</red>")
   303  		l.Add("//"+u+"/attachs/s?sid=1&stype=forums", "<red>[Invalid URL]</red>")
   304  		l.Add("//"+u+"/attachs/?sid=1&stype=forums", "<red>[Invalid URL]</red>")
   305  		l.Add("//"+u+"/attachs/sha256hash.?sid=1&stype=forums", "<red>[Invalid URL]</red>")
   306  		l.Add("//"+u+"/attachs?sid=1&stype=forums", "<red>[Invalid URL]</red>")
   307  		l.Add("//"+u+"/attachs/sha256hash.png", "<a href=\""+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums\"><img src='"+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums'class='postImage'></a>")
   308  		l.Add("//"+u+"/attachs/sha256hash.png?sid=1", "<a href=\""+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums\"><img src='"+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums'class='postImage'></a>")
   309  		l.Add("//"+u+"/attachs/sha256hash.png?stype=forums", "<a href=\""+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums\"><img src='"+fs+"/attachs/sha256hash.png?sid=1&amp;stype=forums'class='postImage'></a>")
   310  
   311  		//l.Add("//"+u+"/attachs/sha256hash.txt?sid=1&stype=forums", "<a class='attach'href=\""+fs+"/attachs/sha256hash.txt?sid=1&amp;stype=forums\"download>Attachment</a>")
   312  		l.Add("//"+u+"/attachs/sha256hash.txt?sid=1&stype=forums", "<div class='attach_box'><div class='attach_info'>"+fs+"/attachs/sha256hash.txt</div><div class='attach_opts'><a class='attach'href=\""+fs+"/attachs/sha256hash.txt?sid=1&amp;stype=forums\">View</a> / <a class='attach'href=\""+fs+"/attachs/sha256hash.txt?sid=1&amp;stype=forums\"download>Download</a></div></div>")
   313  
   314  		l.Add("//example.com/image.png", "<a href=\"//example.com/image.png\"><img src='//example.com/image.png'class='postImage'></a>")
   315  		l.Add("https://example.com/image.png", "<a href=\"https://example.com/image.png\"><img src='https://example.com/image.png'class='postImage'></a>")
   316  		l.Add("http://example.com/image.png", "<a href=\"http://example.com/image.png\"><img src='http://example.com/image.png'class='postImage'></a>")
   317  	}
   318  	local("localhost")
   319  	local("127.0.0.1")
   320  	local("[::1]")
   321  
   322  	l.Add("https://www.youtube.com/watch?v=lalalalala", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   323  	l.Add("https://www.youtube.com/watch?v=lalalalala&t=30s", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala?start=30'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala&t=30s'>https://www.youtube.com/watch?v=lalalalala&t=30s</a></noscript>")
   324  	l.Add("https://www.youtube.com/watch?v=lalalalala&t=1s", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   325  	l.Add("https://www.youtube.com/watch?v=lalalalala&t=1", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   326  	//l.Add("https://www.youtube.com/watch?v=;","<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/;'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch'>https://www.youtube.com/watch</a></noscript>")
   327  	l.Add("https://www.youtube.com/watch?v=d;", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/d'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=d'>https://www.youtube.com/watch?v=d</a></noscript>")
   328  	l.Add("https://www.youtube.com/watch?v=d;d", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/d'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=d'>https://www.youtube.com/watch?v=d</a></noscript>")
   329  	l.Add("https://www.youtube.com/watch?v=alert()", "<red>[Invalid URL]</red>()")
   330  	l.Add("https://www.youtube.com/watch?v=alert()()", "<red>[Invalid URL]</red>()()")
   331  	l.Add("https://www.youtube.com/watch?v=js:alert()", "<red>[Invalid URL]</red>()")
   332  	l.Add("https://www.youtube.com/watch?v='+><script>alert(\"\")</script><+'", "<red>[Invalid URL]</red>'+><script>alert(\"\")</script><+'")
   333  	l.Add("https://www.youtube.com/watch?v='+onready='alert(\"\")'+'", "<red>[Invalid URL]</red>'+onready='alert(\"\")'+'")
   334  	l.Add(" https://www.youtube.com/watch?v=lalalalala", " <iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   335  	l.Add("https://www.youtube.com/watch?v=lalalalala tt", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript> tt")
   336  	l.Add("https://www.youtube.com/watch?v=lalalalala&d=haha", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   337  	l.Add("https://gaming.youtube.com/watch?v=lalalalala", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://gaming.youtube.com/watch?v=lalalalala'>https://gaming.youtube.com/watch?v=lalalalala</a></noscript>")
   338  	l.Add("https://gaming.youtube.com/watch?v=lalalalala&d=haha", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://gaming.youtube.com/watch?v=lalalalala'>https://gaming.youtube.com/watch?v=lalalalala</a></noscript>")
   339  	l.Add("https://youtu.be/lalalalala", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://youtu.be/lalalalala'>https://youtu.be/lalalalala</a></noscript>")
   340  	l.Add("https://m.youtube.com/watch?v=lalalalala", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://m.youtube.com/watch?v=lalalalala'>https://m.youtube.com/watch?v=lalalalala</a></noscript>")
   341  	l.Add("https://m.youtube.com/watch?v=lalalalala&d=haha", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://m.youtube.com/watch?v=lalalalala'>https://m.youtube.com/watch?v=lalalalala</a></noscript>")
   342  	l.Add("http://www.youtube.com/watch?v=lalalalala", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   343  	l.Add("//www.youtube.com/watch?v=lalalalala", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   344  	//l.Add("www.youtube.com/watch?v=lalalalala","<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala'>https://www.youtube.com/watch?v=lalalalala</a></noscript>")
   345  	l.Add("https://www.nicovideo.jp/watch/sm111111", "<iframe class='postIframe'src='https://embed.nicovideo.jp/watch/sm111111?jsapi=1&amp;playerId=1'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.nicovideo.jp/watch/sm111111'>https://www.nicovideo.jp/watch/sm111111</a></noscript>")
   346  	//l.Add("www.nicovideo.jp/watch/sm111111", "<iframe class='postIframe'src='https://embed.nicovideo.jp/watch/sm111111?jsapi=1&amp;playerId=1'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.nicovideo.jp/watch/sm111111'>www.nicovideo.jp/watch/sm111111</a></noscript>")
   347  	//l.Add("www.nicovideo.jp/watch/smlalalalala", "<a href='www.nicovideo.jp/watch/smlalalalala'>www.nicovideo.jp/watch/smlalalalala</a>")
   348  	l.Add("https://www.nicovideo.jp/watch/smlalalalala", "<a rel='ugc'href='https://www.nicovideo.jp/watch/smlalalalala'>www.nicovideo.jp/watch/smlalalalala</a>")
   349  	l.Add("//www.youtube.com/watch?v=lalalalala&t=30s", "<iframe class='postIframe'src='https://www.youtube-nocookie.com/embed/lalalalala?start=30'frameborder=0 allowfullscreen></iframe><noscript><a href='https://www.youtube.com/watch?v=lalalalala&t=30s'>https://www.youtube.com/watch?v=lalalalala&t=30s</a></noscript>")
   350  
   351  	l.Add("#tid-1", "<a href='/topic/1'>#tid-1</a>")
   352  	l.Add("#tid-1#tid-1", "<a href='/topic/1'>#tid-1</a>#tid-1")
   353  	l.Add("##tid-1", "##tid-1")
   354  	l.Add("#@tid-1", "#@tid-1")
   355  	l.Add("# #tid-1", "# #tid-1")
   356  	l.Add("@ #tid-1", "<red>[Invalid Profile]</red>#tid-1")
   357  	l.Add("@#tid-1", "<red>[Invalid Profile]</red>tid-1")
   358  	l.Add("@ #tid-@", "<red>[Invalid Profile]</red>#tid-@")
   359  	l.Add("#tid-1 #tid-1", "<a href='/topic/1'>#tid-1</a> <a href='/topic/1'>#tid-1</a>")
   360  	l.Add("#tid-0", "<red>[Invalid Topic]</red>")
   361  	l.Add("https://"+url+"/#tid-1", "<a rel='ugc'href='https://"+url+"/#tid-1'>"+url+"/#tid-1</a>")
   362  	l.Add("https://"+url+"/?hi=2", "<a rel='ugc'href='https://"+url+"/?hi=2'>"+url+"/?hi=2</a>")
   363  	l.Add("https://"+url+"/?hi=2#t=1", "<a rel='ugc'href='https://"+url+"/?hi=2#t=1'>"+url+"/?hi=2#t=1</a>")
   364  	l.Add("#fid-1", "<a href='/forum/1'>#fid-1</a>")
   365  	l.Add(" #fid-1", " <a href='/forum/1'>#fid-1</a>")
   366  	l.Add("#fid-0", "<red>[Invalid Forum]</red>")
   367  	l.Add(" #fid-0", " <red>[Invalid Forum]</red>")
   368  	l.Add("#", "#")
   369  	l.Add("# ", "# ")
   370  	l.Add(" @", " @")
   371  	l.Add(" #", " #")
   372  	l.Add("#@", "#@")
   373  	l.Add("#@ ", "#@ ")
   374  	l.Add("#@1", "#@1")
   375  	l.Add("#f", "#f")
   376  	l.Add("f#f", "f#f")
   377  	l.Add("f#", "f#")
   378  	l.Add("#ff", "#ff")
   379  	l.Add("#ffffid-0", "#ffffid-0")
   380  	//l.Add("#ffffid-0", "#ffffid-0")
   381  	l.Add("#nid-0", "#nid-0")
   382  	l.Add("#nnid-0", "#nnid-0")
   383  	l.Add("@@", "<red>[Invalid Profile]</red>")
   384  	l.Add("@@ @@", "<red>[Invalid Profile]</red> <red>[Invalid Profile]</red>")
   385  	l.Add("@@1", "<red>[Invalid Profile]</red>1")
   386  	l.Add("@#1", "<red>[Invalid Profile]</red>1")
   387  	l.Add("@##1", "<red>[Invalid Profile]</red>#1")
   388  	l.Add("@2", "<red>[Invalid Profile]</red>")
   389  	l.Add("@2t", "<red>[Invalid Profile]</red>t")
   390  	l.Add("@2 t", "<red>[Invalid Profile]</red> t")
   391  	l.Add("@2 ", "<red>[Invalid Profile]</red> ")
   392  	l.Add("@2 @2", "<red>[Invalid Profile]</red> <red>[Invalid Profile]</red>")
   393  	l.Add("@1", "<a href='/user/admin.1'class='mention'>@Admin</a>")
   394  	l.Add(" @1", " <a href='/user/admin.1'class='mention'>@Admin</a>")
   395  	l.Add("@1t", "<a href='/user/admin.1'class='mention'>@Admin</a>t")
   396  	l.Add("@1 ", "<a href='/user/admin.1'class='mention'>@Admin</a> ")
   397  	l.Add("@1 @1", "<a href='/user/admin.1'class='mention'>@Admin</a> <a href='/user/admin.1'class='mention'>@Admin</a>")
   398  	l.Add("@0", "<red>[Invalid Profile]</red>")
   399  	l.Add("@-1", "<red>[Invalid Profile]</red>1")
   400  
   401  	// TODO: Fix this hack and make the results a bit more reproducible, push the tests further in the process.
   402  	c.GuestUser.Perms.AutoLink = true
   403  	for _, item := range l.Items {
   404  		if res := c.ParseMessage(item.Msg, 1, "forums", nil, nil); res != item.Expects {
   405  			if item.Name != "" {
   406  				t.Error("Name: ", item.Name)
   407  			}
   408  			t.Error("Testing string '" + item.Msg + "'")
   409  			t.Error("Bad output:", "'"+res+"'")
   410  			t.Error("Expected:", "'"+item.Expects+"'")
   411  			break
   412  		}
   413  	}
   414  	c.Config.SslSchema = pre2
   415  
   416  	l = &METriList{nil}
   417  	pre := c.Site.URL // Just in case this is localhost...
   418  	pre2 = c.Config.SslSchema
   419  	c.Site.URL = "example.com"
   420  	c.Config.SslSchema = true
   421  	l.Add("//"+c.Site.URL, "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a>")
   422  	l.Add("//"+c.Site.URL+"\n", "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br>")
   423  	l.Add("//"+c.Site.URL+"\n//"+c.Site.URL, "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br><a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a>")
   424  	for _, item := range l.Items {
   425  		if res := c.ParseMessage(item.Msg, 1, "forums", nil, nil); res != item.Expects {
   426  			if item.Name != "" {
   427  				t.Error("Name: ", item.Name)
   428  			}
   429  			t.Error("Testing string '" + item.Msg + "'")
   430  			t.Error("Bad output:", "'"+res+"'")
   431  			t.Error("Expected:", "'"+item.Expects+"'")
   432  			break
   433  		}
   434  	}
   435  	c.Site.URL = pre
   436  	c.Config.SslSchema = pre2
   437  
   438  	l = &METriList{nil}
   439  	l.Add("//", "//")
   440  	l.Add("//z", "//z")
   441  	l.Add("//"+url, "//"+url)
   442  	l.Add("https://www.youtube.com/watch?v=lalalalala&t=1", "https://www.youtube.com/watch?v=lalalalala&t=1")
   443  	l.Add("#tid-1", "<a href='/topic/1'>#tid-1</a>")
   444  	c.GuestUser.Perms.AutoLink = false
   445  	for _, item := range l.Items {
   446  		if res := c.ParseMessage(item.Msg, 1, "forums", nil, nil); res != item.Expects {
   447  			if item.Name != "" {
   448  				t.Error("Name: ", item.Name)
   449  			}
   450  			t.Error("Testing string '" + item.Msg + "'")
   451  			t.Error("Bad output:", "'"+res+"'")
   452  			t.Error("Expected:", "'"+item.Expects+"'")
   453  			break
   454  		}
   455  	}
   456  
   457  	c.AddHashLinkType("nnid-", func(sb *strings.Builder, msg string, i *int) {
   458  		tid, intLen := c.CoerceIntString(msg[*i:])
   459  		*i += intLen
   460  
   461  		topic, err := c.Topics.Get(tid)
   462  		if err != nil || !c.Forums.Exists(topic.ParentID) {
   463  			sb.Write(c.InvalidTopic)
   464  			return
   465  		}
   466  		c.WriteURL(sb, c.BuildTopicURL("", tid), "#nnid-"+strconv.Itoa(tid))
   467  	})
   468  	res := c.ParseMessage("#nnid-1", 1, "forums", nil, nil)
   469  	expect := "<a href='/topic/1'>#nnid-1</a>"
   470  	if res != expect {
   471  		t.Error("Bad output:", "'"+res+"'")
   472  		t.Error("Expected:", "'"+expect+"'")
   473  	}
   474  
   475  	c.AddHashLinkType("longidnameneedtooverflowhack-", func(sb *strings.Builder, msg string, i *int) {
   476  		tid, intLen := c.CoerceIntString(msg[*i:])
   477  		*i += intLen
   478  
   479  		topic, err := c.Topics.Get(tid)
   480  		if err != nil || !c.Forums.Exists(topic.ParentID) {
   481  			sb.Write(c.InvalidTopic)
   482  			return
   483  		}
   484  		c.WriteURL(sb, c.BuildTopicURL("", tid), "#longidnameneedtooverflowhack-"+strconv.Itoa(tid))
   485  	})
   486  	res = c.ParseMessage("#longidnameneedtooverflowhack-1", 1, "forums", nil, nil)
   487  	expect = "<a href='/topic/1'>#longidnameneedtooverflowhack-1</a>"
   488  	if res != expect {
   489  		t.Error("Bad output:", "'"+res+"'")
   490  		t.Error("Expected:", "'"+expect+"'")
   491  	}
   492  }
   493  
   494  func TestPaginate(t *testing.T) {
   495  	var plist []int
   496  	f := func(i, want int) {
   497  		expect(t, plist[i] == want, fmt.Sprintf("plist[%d] should be %d not %d", i, want, plist[i]))
   498  	}
   499  
   500  	plist = c.Paginate(1, 1, 5)
   501  	expect(t, len(plist) == 1, fmt.Sprintf("len of plist should be 1 not %d", len(plist)))
   502  	f(0, 1)
   503  
   504  	plist = c.Paginate(1, 5, 5)
   505  	expect(t, len(plist) == 5, fmt.Sprintf("len of plist should be 5 not %d", len(plist)))
   506  	f(0, 1)
   507  	f(1, 2)
   508  	f(2, 3)
   509  	f(3, 4)
   510  	f(4, 5)
   511  
   512  	// TODO: More Paginate() tests
   513  	// TODO: Tests for other paginator functions
   514  }