package formatter import ( "testing" "github.com/zelenin/go-tdlib/client" ) func TestNoFormatting(t *testing.T) { markup := Format("abc\ndef", []*client.TextEntity{}, MarkupModeMarkdown) if markup != "abc\ndef" { t.Errorf("No formatting expected, but: %v", markup) } } func TestFormattingSimple(t *testing.T) { markup := Format("👙🐧🐖", []*client.TextEntity{ &client.TextEntity{ Offset: 2, Length: 4, Type: &client.TextEntityTypeBold{}, }, }, MarkupModeMarkdown) if markup != "👙**🐧🐖**" { t.Errorf("Wrong simple formatting: %v", markup) } } func TestFormattingAdjacent(t *testing.T) { markup := Format("a👙🐧🐖", []*client.TextEntity{ &client.TextEntity{ Offset: 3, Length: 2, Type: &client.TextEntityTypeItalic{}, }, &client.TextEntity{ Offset: 5, Length: 2, Type: &client.TextEntityTypeTextUrl{ Url: "https://narayana.im/", }, }, }, MarkupModeMarkdown) if markup != "a👙_🐧_[🐖](https://narayana.im/)" { t.Errorf("Wrong adjacent formatting: %v", markup) } } func TestFormattingAdjacentAndNested(t *testing.T) { markup := Format("👙🐧🐖", []*client.TextEntity{ &client.TextEntity{ Offset: 0, Length: 4, Type: &client.TextEntityTypePre{}, }, &client.TextEntity{ Offset: 0, Length: 2, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 4, Length: 2, Type: &client.TextEntityTypeItalic{}, }, }, MarkupModeMarkdown) if markup != "```\n**👙**🐧\n```_🐖_" { t.Errorf("Wrong adjacent&nested formatting: %v", markup) } } func TestRebalanceTwoZero(t *testing.T) { s1 := insertionStack{ &insertion{Offset: 7}, &insertion{Offset: 8}, } s2 := insertionStack{} s1, s2 = s1.rebalance(s2, 7) if !(len(s1) == 2 && len(s2) == 0 && s1[0].Offset == 7 && s1[1].Offset == 8) { t.Errorf("Wrong rebalance 2–0: %#v %#v", s1, s2) } } func TestRebalanceNeeded(t *testing.T) { s1 := insertionStack{ &insertion{Offset: 7}, &insertion{Offset: 8}, } s2 := insertionStack{ &insertion{Offset: 10}, &insertion{Offset: 9}, } s1, s2 = s1.rebalance(s2, 9) if !(len(s1) == 3 && len(s2) == 1 && s1[0].Offset == 7 && s1[1].Offset == 8 && s1[2].Offset == 9 && s2[0].Offset == 10) { t.Errorf("Wrong rebalance when needed: %#v %#v", s1, s2) } } func TestRebalanceNotNeeded(t *testing.T) { s1 := insertionStack{ &insertion{Offset: 7}, &insertion{Offset: 8}, } s2 := insertionStack{ &insertion{Offset: 10}, &insertion{Offset: 9}, } s1, s2 = s1.rebalance(s2, 8) if !(len(s1) == 2 && len(s2) == 2 && s1[0].Offset == 7 && s1[1].Offset == 8 && s2[0].Offset == 10 && s2[1].Offset == 9) { t.Errorf("Wrong rebalance when not needed: %#v %#v", s1, s2) } } func TestRebalanceLate(t *testing.T) { s1 := insertionStack{ &insertion{Offset: 7}, &insertion{Offset: 8}, } s2 := insertionStack{ &insertion{Offset: 10}, &insertion{Offset: 9}, } s1, s2 = s1.rebalance(s2, 10) if !(len(s1) == 4 && len(s2) == 0 && s1[0].Offset == 7 && s1[1].Offset == 8 && s1[2].Offset == 9 && s1[3].Offset == 10) { t.Errorf("Wrong rebalance when late: %#v %#v", s1, s2) } } func TestIteratorEmpty(t *testing.T) { s := insertionStack{} g := s.NewIterator() v := g() if v != nil { t.Errorf("Empty iterator should return nil but returned %#v", v) } } func TestIterator(t *testing.T) { s := insertionStack{ &insertion{Offset: 7}, &insertion{Offset: 8}, } g := s.NewIterator() v := g() if v == nil || v.Offset != 7 { t.Errorf("Wrong insertion instead of 7: %#v", v) } v = g() if v == nil || v.Offset != 8 { t.Errorf("Wrong insertion instead of 8: %#v", v) } v = g() if v != nil { t.Errorf("nil should be returned after end, %#v instead", v) } v = g() if v != nil { t.Errorf("Further attempts should return nil too, %#v instead", v) } } func TestSortEntities(t *testing.T) { entities := []*client.TextEntity{ &client.TextEntity{ Offset: 3, Length: 2, }, &client.TextEntity{ Offset: 5, Length: 2, }, &client.TextEntity{ Offset: 7, Length: 2, }, &client.TextEntity{ Offset: 6, Length: 1, }, &client.TextEntity{ Offset: 5, Length: 1, }, } entities = SortEntities(entities) if !(len(entities) == 5 && entities[0].Offset == 3 && entities[0].Length == 2 && entities[1].Offset == 5 && entities[1].Length == 2 && entities[2].Offset == 5 && entities[2].Length == 1 && entities[3].Offset == 6 && entities[3].Length == 1 && entities[4].Offset == 7 && entities[4].Length == 2) { t.Errorf("Wrong sorting order: %#v", entities) } } func TestSortEmpty(t *testing.T) { entities := []*client.TextEntity{} entities = SortEntities(entities) if len(entities) != 0 { t.Errorf("Empty entities set sorting error: %#v", entities) } } func TestNoFormattingXEP0393(t *testing.T) { markup := Format("abc\ndef", []*client.TextEntity{}, MarkupModeXEP0393) if markup != "abc\ndef" { t.Errorf("No formatting expected, but: %v", markup) } } func TestFormattingXEP0393Simple(t *testing.T) { markup := Format("👙🐧🐖", []*client.TextEntity{ &client.TextEntity{ Offset: 2, Length: 4, Type: &client.TextEntityTypeBold{}, }, }, MarkupModeXEP0393) if markup != "👙*🐧🐖*" { t.Errorf("Wrong simple formatting: %v", markup) } } func TestFormattingXEP0393Adjacent(t *testing.T) { markup := Format("a👙🐧🐖", []*client.TextEntity{ &client.TextEntity{ Offset: 3, Length: 2, Type: &client.TextEntityTypeItalic{}, }, &client.TextEntity{ Offset: 5, Length: 2, Type: &client.TextEntityTypeTextUrl{ Url: "https://narayana.im/", }, }, }, MarkupModeXEP0393) if markup != "a👙_🐧_🐖 " { t.Errorf("Wrong adjacent formatting: %v", markup) } } func TestFormattingXEP0393AdjacentAndNested(t *testing.T) { markup := Format("👙🐧🐖", []*client.TextEntity{ &client.TextEntity{ Offset: 0, Length: 4, Type: &client.TextEntityTypePre{}, }, &client.TextEntity{ Offset: 0, Length: 2, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 4, Length: 2, Type: &client.TextEntityTypeItalic{}, }, }, MarkupModeXEP0393) if markup != "```\n*👙*🐧\n```_🐖_" { t.Errorf("Wrong adjacent&nested formatting: %v", markup) } } func TestFormattingXEP0393AdjacentItalicBoldItalic(t *testing.T) { markup := Format("раса двуногих крысолюдей, которую так редко замечают, что многие отрицают само их существование", []*client.TextEntity{ &client.TextEntity{ Offset: 0, Length: 26, Type: &client.TextEntityTypeItalic{}, }, &client.TextEntity{ Offset: 26, Length: 69, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 26, Length: 69, Type: &client.TextEntityTypeItalic{}, }, }, MarkupModeXEP0393) if markup != "_раса двуногих крысолюдей, *которую так редко замечают, что многие отрицают само их существование*_" { t.Errorf("Wrong adjacent italic/bold-italic formatting: %v", markup) } } func TestFormattingXEP0393MultipleAdjacent(t *testing.T) { markup := Format("abcde", []*client.TextEntity{ &client.TextEntity{ Offset: 1, Length: 1, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 2, Length: 1, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 3, Length: 1, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 4, Length: 1, Type: &client.TextEntityTypeItalic{}, }, }, MarkupModeXEP0393) if markup != "a*bcd*_e_" { t.Errorf("Wrong multiple adjacent formatting: %v", markup) } } func TestFormattingXEP0393Intersecting(t *testing.T) { markup := Format("abcde", []*client.TextEntity{ &client.TextEntity{ Offset: 1, Length: 1, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 2, Length: 3, Type: &client.TextEntityTypeItalic{}, }, &client.TextEntity{ Offset: 2, Length: 1, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 3, Length: 1, Type: &client.TextEntityTypeBold{}, }, }, MarkupModeXEP0393) if markup != "a*b*_*cd*e_" { t.Errorf("Wrong intersecting formatting: %v", markup) } } func TestFormattingXEP0393InlineCode(t *testing.T) { markup := Format("Is Gajim a thing?\n\necho 'Hello'\necho 'world'\n\nhruck(", []*client.TextEntity{ &client.TextEntity{ Offset: 3, Length: 5, Type: &client.TextEntityTypeCode{}, }, &client.TextEntity{ Offset: 19, Length: 25, Type: &client.TextEntityTypePre{}, }, }, MarkupModeXEP0393) if markup != "Is `Gajim` a thing?\n\n```\necho 'Hello'\necho 'world'\n```\n\nhruck(" { t.Errorf("Wrong intersecting formatting: %v", markup) } } func TestFormattingMarkdownStrikethrough(t *testing.T) { markup := Format("Everyone dislikes cake.", []*client.TextEntity{ &client.TextEntity{ Offset: 9, Length: 3, Type: &client.TextEntityTypeStrikethrough{}, }, }, MarkupModeMarkdown) if markup != "Everyone ~~dis~~likes cake." { t.Errorf("Wrong strikethrough formatting: %v", markup) } } func TestFormattingXEP0393Strikethrough(t *testing.T) { markup := Format("Everyone dislikes cake.", []*client.TextEntity{ &client.TextEntity{ Offset: 9, Length: 3, Type: &client.TextEntityTypeStrikethrough{}, }, }, MarkupModeXEP0393) if markup != "Everyone ~dis~likes cake." { t.Errorf("Wrong strikethrough formatting: %v", markup) } } func TestClaspLeft(t *testing.T) { text := textToDoubledRunes("a b c") entities := []*client.TextEntity{ &client.TextEntity{ Offset: 1, Length: 2, }, } entities = ClaspDirectives(text, entities) if !(len(entities) == 1 && entities[0].Offset == 2 && entities[0].Length == 1) { t.Errorf("Wrong claspleft: %#v", entities) } } func TestClaspBoth(t *testing.T) { text := textToDoubledRunes("a b c") entities := []*client.TextEntity{ &client.TextEntity{ Offset: 1, Length: 3, }, } entities = ClaspDirectives(text, entities) if !(len(entities) == 1 && entities[0].Offset == 2 && entities[0].Length == 1) { t.Errorf("Wrong claspboth: %#v", entities) } } func TestClaspNotNeeded(t *testing.T) { text := textToDoubledRunes(" abc ") entities := []*client.TextEntity{ &client.TextEntity{ Offset: 1, Length: 3, }, } entities = ClaspDirectives(text, entities) if !(len(entities) == 1 && entities[0].Offset == 1 && entities[0].Length == 3) { t.Errorf("Wrong claspnotneeded: %#v", entities) } } func TestClaspNested(t *testing.T) { text := textToDoubledRunes("a b c") entities := []*client.TextEntity{ &client.TextEntity{ Offset: 1, Length: 3, }, &client.TextEntity{ Offset: 2, Length: 2, }, } entities = ClaspDirectives(text, entities) if !(len(entities) == 2 && entities[0].Offset == 2 && entities[0].Length == 1 && entities[1].Offset == 2 && entities[1].Length == 1) { t.Errorf("Wrong claspnested: %#v", entities) } } func TestClaspEmoji(t *testing.T) { text := textToDoubledRunes("a 🐖 c") entities := []*client.TextEntity{ &client.TextEntity{ Offset: 1, Length: 4, }, } entities = ClaspDirectives(text, entities) if !(len(entities) == 1 && entities[0].Offset == 2 && entities[0].Length == 2) { t.Errorf("Wrong claspemoji: %#v", entities) } } func TestNoNewlineBlockquoteXEP0393(t *testing.T) { markup := Format("yes it can i think", []*client.TextEntity{ &client.TextEntity{ Offset: 4, Length: 6, Type: &client.TextEntityTypeBlockQuote{}, }, }, MarkupModeXEP0393) if markup != "yes \n> it can\n i think" { t.Errorf("Wrong blockquote formatting: %v", markup) } } func TestNoNewlineBlockquoteMarkdown(t *testing.T) { markup := Format("yes it can i think", []*client.TextEntity{ &client.TextEntity{ Offset: 4, Length: 6, Type: &client.TextEntityTypeBlockQuote{}, }, }, MarkupModeMarkdown) if markup != "yes \n> it can\n\n i think" { t.Errorf("Wrong blockquote formatting: %v", markup) } } func TestMultilineBlockquoteXEP0393(t *testing.T) { markup := Format("hruck\npuck\n\nshuck\ntext", []*client.TextEntity{ &client.TextEntity{ Offset: 0, Length: 17, Type: &client.TextEntityTypeBlockQuote{}, }, }, MarkupModeXEP0393) if markup != "> hruck\n> puck\n> \n> shuck\ntext" { t.Errorf("Wrong blockquote formatting: %v", markup) } } func TestMultilineBlockquoteMarkdown(t *testing.T) { markup := Format("hruck\npuck\n\nshuck\ntext", []*client.TextEntity{ &client.TextEntity{ Offset: 0, Length: 17, Type: &client.TextEntityTypeBlockQuote{}, }, }, MarkupModeMarkdown) if markup != "> hruck\npuck\n\n> shuck\n\ntext" { t.Errorf("Wrong blockquote formatting: %v", markup) } } func TestMixedBlockquoteXEP0393(t *testing.T) { markup := Format("hruck\npuck\nshuck\ntext", []*client.TextEntity{ &client.TextEntity{ Offset: 0, Length: 16, Type: &client.TextEntityTypeBlockQuote{}, }, &client.TextEntity{ Offset: 0, Length: 16, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 0, Length: 10, Type: &client.TextEntityTypeItalic{}, }, &client.TextEntity{ Offset: 7, Length: 2, Type: &client.TextEntityTypeStrikethrough{}, }, }, MarkupModeXEP0393) if markup != "> *_hruck\n> p~uc~k_\n> shuck*\ntext" { t.Errorf("Wrong blockquote formatting: %v", markup) } } func TestMixedBlockquoteMarkdown(t *testing.T) { markup := Format("hruck\npuck\nshuck\ntext", []*client.TextEntity{ &client.TextEntity{ Offset: 0, Length: 16, Type: &client.TextEntityTypeBlockQuote{}, }, &client.TextEntity{ Offset: 0, Length: 16, Type: &client.TextEntityTypeBold{}, }, &client.TextEntity{ Offset: 0, Length: 10, Type: &client.TextEntityTypeItalic{}, }, &client.TextEntity{ Offset: 7, Length: 2, Type: &client.TextEntityTypeStrikethrough{}, }, }, MarkupModeMarkdown) if markup != "> **_hruck\np~~uc~~k_\nshuck**\n\ntext" { t.Errorf("Wrong blockquote formatting: %v", markup) } }