package main import ( "fmt" "strconv" "strings" "testing" c "git.tuxpa.in/a/gosora/common" ) func TestPreparser(t *testing.T) { miscinit(t) if !c.PluginsInited { c.InitPlugins() } l := &METriList{nil} // 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 l.Add("", "") l.Add(" ", "") l.Add(" hi", "hi") l.Add("hi ", "hi") l.Add("hi", "hi") l.Add(":grinning:", "πŸ˜€") l.Add(":grinning: :grinning:", "πŸ˜€ πŸ˜€") l.Add(" :grinning: ", "πŸ˜€") l.Add(": :grinning: :", ": πŸ˜€ :") l.Add("::grinning::", ":πŸ˜€:") //l.Add("d:grinning:d", "d:grinning:d") // todo l.Add("d :grinning: d", "d πŸ˜€ d") l.Add("πŸ˜€", "πŸ˜€") l.Add(" ", "") l.Add("

", "") l.Add("

", "") l.Add("

", "") l.Add("<", "<") l.Add(">", ">") l.Add("", "<meow>") l.Add("<", "&lt;") l.Add("&", "&") // Note: strings.TrimSpace strips newlines, if there's nothing before or after them l.Add("
", "") l.Add("
", "") l.Add("\\n", "\n", "") l.Add("\\n\\n", "\n\n", "") l.Add("\\n\\n\\n", "\n\n\n", "") l.Add("\\r\\n", "\r\n", "") // Windows style line ending l.Add("\\n\\r", "\n\r", "") l.Add("ho
ho", "ho\n\nho") l.Add("ho
ho", "ho\n\nho") l.Add("ho\\nho", "ho\nho", "ho\nho") l.Add("ho\\n\\nho", "ho\n\nho", "ho\n\nho") //l.Add("ho\\n\\n\\n\\nho", "ho\n\n\n\nho", "ho\n\n\nho") l.Add("ho\\r\\nho", "ho\r\nho", "ho\nho") // Windows style line ending l.Add("ho\\n\\rho", "ho\n\rho", "ho\nho") l.Add("", "") l.Add("hi", "hi") l.Add("h", "h") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") // Grammarly fix l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("
hi
", "<div>hi</div>") l.Add("hi", "hi") // This is stripped since the editor (Trumbowyg) likes blasting useless spans l.Add("hi", "hi") l.Add("hi", "hi") l.Add(">hi", ">hi") l.Add("hi", "hi") l.Add("hi", "hi</b>") l.Add("", "</b>") l.Add("", "</del>") l.Add("", "</strong>") l.Add("", "") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("hi", "hi") l.Add("", "") l.Add("", "") l.Add("", "") l.Add("", "") l.Add("", "") l.Add("

t

", "

t

") l.Add("

t

", "

t

") l.Add("

t

", "

t

") l.Add("<>", "<></>") l.Add("<>", "</><>") l.Add("<>", "<>") l.Add("", "</>") l.Add("

hi

", "hi") l.Add("

", "") l.Add("
hi
", "
hi
") l.Add("
hi
", "
hi
") l.Add("
hi
", "
<meow>hi</meow>
") l.Add("\\
hi
", "<blockquote>hi</blockquote>") //l.Add("\\\\
hi
", "\\
<meow>hi</meow>
") // TODO: Double escapes should print a literal backslash //l.Add("<blockquote>hi</blockquote>", "<blockquote>hi</blockquote>") // TODO: Stop double-entitising this l.Add("\\
hi
\\
hi
", "<blockquote>hi</blockquote><blockquote>hi</blockquote>") l.Add("\\Admin", "<a itemprop="author">Admin</a>") l.Add("
\\Admin
", "
<a itemprop="author">Admin</a>
") l.Add("\n
\\Admin
\n", "
<a itemprop="author">Admin</a>
") l.Add("tt\n
\\Admin
\ntt", "tt\n
<a itemprop="author">Admin</a>
\ntt") l.Add("@", "@") l.Add("@Admin", "@1") l.Add("@Bah", "@Bah") l.Add(" @Admin", "@1") l.Add("\n@Admin", "@1") l.Add("@Admin\n", "@1") l.Add("@Admin\ndd", "@1\ndd") l.Add("d@Admin", "d@Admin") l.Add("\\@Admin", "@Admin") l.Add("@ε…ƒζ°—", "@ε…ƒζ°—") // TODO: More tests for unicode names? //l.Add("\\\\@Admin", "@1") //l.Add("byte 0", string([]byte{0}), "") l.Add("byte 'a'", string([]byte{'a'}), "a") //l.Add("byte 255", string([]byte{255}), "") //l.Add("rune 0", string([]rune{0}), "") // TODO: Do a test with invalid UTF-8 input for _, item := range l.Items { if res := c.PreparseMessage(item.Msg); res != item.Expects { if item.Name != "" { t.Error("Name: ", item.Name) } t.Error("Testing string '" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") //t.Error("Ouput in bytes:", []byte(res)) t.Error("Expected:", "'"+item.Expects+"'") } } } func TestParser(t *testing.T) { miscinit(t) if !c.PluginsInited { c.InitPlugins() } l := &METriList{nil} url := "git.tuxpa.in/a/gosora" eurl := "" + url + "" l.Add("", "") l.Add("haha", "haha") l.Add(":P", "πŸ˜›") l.Add(" :P ", " πŸ˜› ") l.Add(":p", "πŸ˜›") l.Add("d:p", "d:p") l.Add(":pd", "πŸ˜›d") l.Add(":pdd", "πŸ˜›dd") l.Add(":pddd", "πŸ˜›ddd") l.Add(":p d", "πŸ˜› d") l.Add(":p dd", "πŸ˜› dd") l.Add(":p ddd", "πŸ˜› ddd") //l.Add(":p:p:p", "πŸ˜›πŸ˜›πŸ˜›") l.Add(":p:p:p", "πŸ˜›:p:p") l.Add(":p :p", "πŸ˜› πŸ˜›") l.Add(":p :p :p", "πŸ˜› πŸ˜› πŸ˜›") l.Add(":p :p :p :p", "πŸ˜› πŸ˜› πŸ˜› πŸ˜›") l.Add(":p :p :p", "πŸ˜› πŸ˜› πŸ˜›") l.Add("word:p", "word:p") l.Add("word:pword", "word:pword") l.Add(":pword", "πŸ˜›word") // TODO: Change the semantics on this to detect the succeeding character? l.Add("word :p", "word πŸ˜›") l.Add(":p word", "πŸ˜› word") l.Add("t", "t") l.Add("//", "//") l.Add("http://", "[Invalid URL]") //l.Add("https://", "[Invalid URL]") l.Add("ipfs://", "[Invalid URL]") l.Add("ftp://", "[Invalid URL]") l.Add("git://", "[Invalid URL]") l.Add("ssh://", "ssh://") l.Add("fff://", "fff://") l.Add("// ", "// ") l.Add("// //", "// //") l.Add("// // //", "// // //") l.Add("http:// ", "[Invalid URL] ") l.Add("https:// ", "[Invalid URL] ") l.Add("ftp:// ", "[Invalid URL] ") l.Add("git:// ", "[Invalid URL] ") l.Add("ssh:// ", "ssh:// ") l.Add("fff:// ", "fff:// ") l.Add("//t", "t") l.Add("// t", "// t") l.Add("http:// t", "[Invalid URL] t") l.Add("g", "g") l.Add("g/", "g/") l.Add("g//", "g//") l.Add("/g", "/g") l.Add("/gg", "/gg") l.Add("/g/", "/g/") l.Add("hi", "hi") l.Add("hit", "hit") l.Add("hit:", "hit:") l.Add("hit:/", "hit:/") l.Add("hit://", "hit://") l.Add("hit://t", "hit://t") l.Add("h", "h") l.Add("ht", "ht") l.Add("htt", "htt") l.Add("http", "http") l.Add("http:", "http:") //t l.Add("http:/", "http:/") //t l.Add("http:/d", "http:/d") l.Add("http:d", "http:d") l.Add("https:", "https:") l.Add("gttps:", "gttps:") l.Add("gttps:/", "gttps:/") l.Add("gttps://", "gttps://") l.Add("ftp:", "ftp:") l.Add("git:", "git:") l.Add("ssh:", "ssh:") l.Add("http", "http") l.Add("https", "https") l.Add("ftp", "ftp") l.Add("git", "git") l.Add("ssh", "ssh") l.Add("ht", "ht") l.Add("htt", "htt") l.Add("ft", "ft") l.Add("gi", "gi") l.Add("ss", "ss") l.Add("haha\nhaha\nhaha", "haha
haha
haha") l.Add("//"+url, eurl) l.Add("//a", "a") l.Add(" //a", " a") l.Add("//a ", "a ") l.Add(" //a ", " a ") l.Add("d //a ", "d a ") l.Add("ddd ddd //a ", "ddd ddd a ") l.Add("https://"+url, ""+url+"") l.Add("https://t", "t") l.Add("https://en.wikipedia.org/wiki/First_they_came_...", "en.wikipedia.org/wiki/First_they_came_...") // this frequently fails in some chat clients, we should make sure that doesn't happen here l.Add("http://"+url, ""+url+"") l.Add("#http://"+url, "#http://"+url) l.Add("@http://"+url, "[Invalid Profile]ttp://"+url) l.Add("//"+url+"\n", ""+url+"
") l.Add("\n//"+url, "
"+eurl) l.Add("\n//"+url+"\n", "
"+eurl+"
") l.Add("\n//"+url+"\n\n", "
"+eurl+"

") l.Add("//"+url+"\n//"+url, eurl+"
"+eurl) l.Add("//"+url+" //"+url, eurl+" "+eurl) l.Add("//"+url+" //"+url, eurl+" "+eurl) //l.Add("//"+url+"//"+url, eurl+""+eurl) //l.Add("//"+url+"|//"+url, eurl+"|"+eurl) l.Add("//"+url+"|//"+url, "[Invalid URL]|//"+url) l.Add("//"+url+"//"+url, ""+url+"//"+url+"") l.Add("//"+url+"\n\n//"+url, eurl+"

"+eurl) pre2 := c.Config.SslSchema c.Config.SslSchema = true local := func(u string) { s := "//" + c.Site.URL fs := "http://" + c.Site.URL ipns := "ipns://" + c.Site.URL if c.Config.SslSchema { s = "https:" + s fs = "https://" + c.Site.URL } l.Add("//"+u, ""+c.Site.URL+"") // TODO: Strip redundant slashes? l.Add("//"+u+"/", ""+c.Site.URL+"/") l.Add("//"+u+"//", ""+c.Site.URL+"//") l.Add("//"+u+"\n", ""+c.Site.URL+"
") l.Add("//"+u+"\n//"+u, ""+c.Site.URL+"
"+c.Site.URL+"") l.Add("http://"+u, ""+c.Site.URL+"") l.Add("https://"+u, ""+c.Site.URL+"") l.Add("ipfs://testthis", "ipfs://testthis") l.Add(ipns, ""+c.Site.URL+"") l.Add("//"+u+"/attachs/sha256hash.webm?sid=1&stype=forums", "") l.Add("//"+u+"/attachs/sha256hash.webm", "") l.Add("//"+u+"/attachs/sha256hash.webm?sid=1", "") l.Add("//"+u+"/attachs/sha256hash.webm?stype=forums", "") l.Add("//"+u+"/attachs/sha256hash.mp3?sid=1&stype=forums", "") l.Add("//"+u+"/attachs/sha256hash.mp3", "") l.Add("//"+u+"/attachs/sha256hash.mp3?sid=1", "") l.Add("//"+u+"/attachs/sha256hash.mp3?stype=forums", "") l.Add("//"+u+"/attachs/sha256hash.png?sid=1&stype=forums", "") l.Add("//"+u+"/attachs/sha256hash?sid=1&stype=forums", "[Invalid URL]") l.Add("//"+u+"/attachs/s?sid=1&stype=forums", "[Invalid URL]") l.Add("//"+u+"/attachs/?sid=1&stype=forums", "[Invalid URL]") l.Add("//"+u+"/attachs/sha256hash.?sid=1&stype=forums", "[Invalid URL]") l.Add("//"+u+"/attachs?sid=1&stype=forums", "[Invalid URL]") l.Add("//"+u+"/attachs/sha256hash.png", "") l.Add("//"+u+"/attachs/sha256hash.png?sid=1", "") l.Add("//"+u+"/attachs/sha256hash.png?stype=forums", "") //l.Add("//"+u+"/attachs/sha256hash.txt?sid=1&stype=forums", "Attachment") l.Add("//"+u+"/attachs/sha256hash.txt?sid=1&stype=forums", "
"+fs+"/attachs/sha256hash.txt
") l.Add("//example.com/image.png", "") l.Add("https://example.com/image.png", "") l.Add("http://example.com/image.png", "") } local("localhost") local("127.0.0.1") local("[::1]") l.Add("https://www.youtube.com/watch?v=lalalalala", "") l.Add("https://www.youtube.com/watch?v=lalalalala&t=30s", "") l.Add("https://www.youtube.com/watch?v=lalalalala&t=1s", "") l.Add("https://www.youtube.com/watch?v=lalalalala&t=1", "") //l.Add("https://www.youtube.com/watch?v=;","") l.Add("https://www.youtube.com/watch?v=d;", "") l.Add("https://www.youtube.com/watch?v=d;d", "") l.Add("https://www.youtube.com/watch?v=alert()", "[Invalid URL]()") l.Add("https://www.youtube.com/watch?v=alert()()", "[Invalid URL]()()") l.Add("https://www.youtube.com/watch?v=js:alert()", "[Invalid URL]()") l.Add("https://www.youtube.com/watch?v='+><+'", "[Invalid URL]'+><+'") l.Add("https://www.youtube.com/watch?v='+onready='alert(\"\")'+'", "[Invalid URL]'+onready='alert(\"\")'+'") l.Add(" https://www.youtube.com/watch?v=lalalalala", " ") l.Add("https://www.youtube.com/watch?v=lalalalala tt", " tt") l.Add("https://www.youtube.com/watch?v=lalalalala&d=haha", "") l.Add("https://gaming.youtube.com/watch?v=lalalalala", "") l.Add("https://gaming.youtube.com/watch?v=lalalalala&d=haha", "") l.Add("https://youtu.be/lalalalala", "") l.Add("https://m.youtube.com/watch?v=lalalalala", "") l.Add("https://m.youtube.com/watch?v=lalalalala&d=haha", "") l.Add("http://www.youtube.com/watch?v=lalalalala", "") l.Add("//www.youtube.com/watch?v=lalalalala", "") //l.Add("www.youtube.com/watch?v=lalalalala","") l.Add("https://www.nicovideo.jp/watch/sm111111", "") //l.Add("www.nicovideo.jp/watch/sm111111", "") //l.Add("www.nicovideo.jp/watch/smlalalalala", "www.nicovideo.jp/watch/smlalalalala") l.Add("https://www.nicovideo.jp/watch/smlalalalala", "www.nicovideo.jp/watch/smlalalalala") l.Add("//www.youtube.com/watch?v=lalalalala&t=30s", "") l.Add("#tid-1", "#tid-1") l.Add("#tid-1#tid-1", "#tid-1#tid-1") l.Add("##tid-1", "##tid-1") l.Add("#@tid-1", "#@tid-1") l.Add("# #tid-1", "# #tid-1") l.Add("@ #tid-1", "[Invalid Profile]#tid-1") l.Add("@#tid-1", "[Invalid Profile]tid-1") l.Add("@ #tid-@", "[Invalid Profile]#tid-@") l.Add("#tid-1 #tid-1", "#tid-1 #tid-1") l.Add("#tid-0", "[Invalid Topic]") l.Add("https://"+url+"/#tid-1", ""+url+"/#tid-1") l.Add("https://"+url+"/?hi=2", ""+url+"/?hi=2") l.Add("https://"+url+"/?hi=2#t=1", ""+url+"/?hi=2#t=1") l.Add("#fid-1", "#fid-1") l.Add(" #fid-1", " #fid-1") l.Add("#fid-0", "[Invalid Forum]") l.Add(" #fid-0", " [Invalid Forum]") l.Add("#", "#") l.Add("# ", "# ") l.Add(" @", " @") l.Add(" #", " #") l.Add("#@", "#@") l.Add("#@ ", "#@ ") l.Add("#@1", "#@1") l.Add("#f", "#f") l.Add("f#f", "f#f") l.Add("f#", "f#") l.Add("#ff", "#ff") l.Add("#ffffid-0", "#ffffid-0") //l.Add("#ffffid-0", "#ffffid-0") l.Add("#nid-0", "#nid-0") l.Add("#nnid-0", "#nnid-0") l.Add("@@", "[Invalid Profile]") l.Add("@@ @@", "[Invalid Profile] [Invalid Profile]") l.Add("@@1", "[Invalid Profile]1") l.Add("@#1", "[Invalid Profile]1") l.Add("@##1", "[Invalid Profile]#1") l.Add("@2", "[Invalid Profile]") l.Add("@2t", "[Invalid Profile]t") l.Add("@2 t", "[Invalid Profile] t") l.Add("@2 ", "[Invalid Profile] ") l.Add("@2 @2", "[Invalid Profile] [Invalid Profile]") l.Add("@1", "@Admin") l.Add(" @1", " @Admin") l.Add("@1t", "@Admint") l.Add("@1 ", "@Admin ") l.Add("@1 @1", "@Admin @Admin") l.Add("@0", "[Invalid Profile]") l.Add("@-1", "[Invalid Profile]1") // TODO: Fix this hack and make the results a bit more reproducible, push the tests further in the process. c.GuestUser.Perms.AutoLink = true for _, item := range l.Items { if res := c.ParseMessage(item.Msg, 1, "forums", nil, nil); res != item.Expects { if item.Name != "" { t.Error("Name: ", item.Name) } t.Error("Testing string '" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") t.Error("Expected:", "'"+item.Expects+"'") break } } c.Config.SslSchema = pre2 l = &METriList{nil} pre := c.Site.URL // Just in case this is localhost... pre2 = c.Config.SslSchema c.Site.URL = "example.com" c.Config.SslSchema = true l.Add("//"+c.Site.URL, ""+c.Site.URL+"") l.Add("//"+c.Site.URL+"\n", ""+c.Site.URL+"
") l.Add("//"+c.Site.URL+"\n//"+c.Site.URL, ""+c.Site.URL+"
"+c.Site.URL+"") for _, item := range l.Items { if res := c.ParseMessage(item.Msg, 1, "forums", nil, nil); res != item.Expects { if item.Name != "" { t.Error("Name: ", item.Name) } t.Error("Testing string '" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") t.Error("Expected:", "'"+item.Expects+"'") break } } c.Site.URL = pre c.Config.SslSchema = pre2 l = &METriList{nil} l.Add("//", "//") l.Add("//z", "//z") l.Add("//"+url, "//"+url) l.Add("https://www.youtube.com/watch?v=lalalalala&t=1", "https://www.youtube.com/watch?v=lalalalala&t=1") l.Add("#tid-1", "#tid-1") c.GuestUser.Perms.AutoLink = false for _, item := range l.Items { if res := c.ParseMessage(item.Msg, 1, "forums", nil, nil); res != item.Expects { if item.Name != "" { t.Error("Name: ", item.Name) } t.Error("Testing string '" + item.Msg + "'") t.Error("Bad output:", "'"+res+"'") t.Error("Expected:", "'"+item.Expects+"'") break } } c.AddHashLinkType("nnid-", func(sb *strings.Builder, msg string, i *int) { tid, intLen := c.CoerceIntString(msg[*i:]) *i += intLen topic, err := c.Topics.Get(tid) if err != nil || !c.Forums.Exists(topic.ParentID) { sb.Write(c.InvalidTopic) return } c.WriteURL(sb, c.BuildTopicURL("", tid), "#nnid-"+strconv.Itoa(tid)) }) res := c.ParseMessage("#nnid-1", 1, "forums", nil, nil) expect := "#nnid-1" if res != expect { t.Error("Bad output:", "'"+res+"'") t.Error("Expected:", "'"+expect+"'") } c.AddHashLinkType("longidnameneedtooverflowhack-", func(sb *strings.Builder, msg string, i *int) { tid, intLen := c.CoerceIntString(msg[*i:]) *i += intLen topic, err := c.Topics.Get(tid) if err != nil || !c.Forums.Exists(topic.ParentID) { sb.Write(c.InvalidTopic) return } c.WriteURL(sb, c.BuildTopicURL("", tid), "#longidnameneedtooverflowhack-"+strconv.Itoa(tid)) }) res = c.ParseMessage("#longidnameneedtooverflowhack-1", 1, "forums", nil, nil) expect = "#longidnameneedtooverflowhack-1" if res != expect { t.Error("Bad output:", "'"+res+"'") t.Error("Expected:", "'"+expect+"'") } } func TestPaginate(t *testing.T) { var plist []int f := func(i, want int) { expect(t, plist[i] == want, fmt.Sprintf("plist[%d] should be %d not %d", i, want, plist[i])) } plist = c.Paginate(1, 1, 5) expect(t, len(plist) == 1, fmt.Sprintf("len of plist should be 1 not %d", len(plist))) f(0, 1) plist = c.Paginate(1, 5, 5) expect(t, len(plist) == 5, fmt.Sprintf("len of plist should be 5 not %d", len(plist))) f(0, 1) f(1, 2) f(2, 3) f(3, 4) f(4, 5) // TODO: More Paginate() tests // TODO: Tests for other paginator functions }