// Copyright 2013 by Dobrosław Żybort. All rights reserved. // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package slug import ( "testing" ) //============================================================================= func TestSlugMake(t *testing.T) { var testCases = []struct { in string want string }{ {"DOBROSLAWZYBORT", "dobroslawzybort"}, {"Dobroslaw Zybort", "dobroslaw-zybort"}, {" Dobroslaw Zybort ?", "dobroslaw-zybort"}, {"Dobrosław Żybort", "dobroslaw-zybort"}, {"Ala ma 6 kotów.", "ala-ma-6-kotow"}, {"áÁàÀãÃâÂäÄąĄą̊Ą̊", "aaaaaaaaaaaaaa"}, {"ćĆĉĈçÇ", "cccccc"}, {"éÉèÈẽẼêÊëËęĘ", "eeeeeeeeeeee"}, {"íÍìÌĩĨîÎïÏįĮ", "iiiiiiiiiiii"}, {"łŁ", "ll"}, {"ńŃ", "nn"}, {"óÓòÒõÕôÔöÖǫǪǭǬø", "ooooooooooooooo"}, {"śŚ", "ss"}, {"úÚùÙũŨûÛüÜųŲ", "uuuuuuuuuuuu"}, {"y̨Y̨", "yy"}, {"źŹżŹ", "zzzz"}, {"·/,:;`˜'\"", ""}, {"2000–2013", "2000-2013"}, {"style—not", "style-not"}, {"test_slug", "test_slug"}, {"Æ", "ae"}, {"Ich heiße", "ich-heisse"}, {"This & that", "this-and-that"}, {"fácil €", "facil-eu"}, {"smile ☺", "smile"}, {"Hellö Wörld хелло ворлд", "hello-world-khello-vorld"}, {"\"C'est déjà l’été.\"", "cest-deja-lete"}, {"jaja---lol-méméméoo--a", "jaja-lol-mememeoo-a"}, {"影師", "ying-shi"}, } for index, st := range testCases { got := Make(st.in) if got != st.want { t.Errorf( "%d. Make(%#v) = %#v; want %#v", index, st.in, got, st.want) } } } func TestSlugMakeLang(t *testing.T) { var testCases = []struct { lang string in string want string }{ {"en", "This & that", "this-and-that"}, {"de", "This & that", "this-und-that"}, {"pl", "This & that", "this-i-that"}, {"es", "This & that", "this-y-that"}, {"gr", "This & that", "this-kai-that"}, {"test", "This & that", "this-and-that"}, // unknown lang, fallback to "en" } for index, smlt := range testCases { got := MakeLang(smlt.in, smlt.lang) if got != smlt.want { t.Errorf( "%d. MakeLang(%#v, %#v) = %#v; want %#v", index, smlt.in, smlt.lang, got, smlt.want) } } } func TestSlugMakeUserSubstituteLang(t *testing.T) { var testCases = []struct { cSub map[string]string lang string in string want string }{ {map[string]string{"'": " "}, "en", "That's great", "that-s-great"}, {map[string]string{"&": "or"}, "en", "This & that", "this-or-that"}, // by default "&" => "and" {map[string]string{"&": "or"}, "de", "This & that", "this-or-that"}, // by default "&" => "und" {map[string]string{"&": "or", "@": "the"}, "de", "@ This & that", "the-this-or-that"}, // by default "&" => "und", "@" => "an" } for index, smust := range testCases { CustomSub = smust.cSub got := MakeLang(smust.in, smust.lang) if got != smust.want { t.Errorf( "%d. %#v; MakeLang(%#v, %#v) = %#v; want %#v", index, smust.cSub, smust.in, smust.lang, got, smust.want) } } } func TestSlugMakeSubstituteOrderLang(t *testing.T) { // Always substitute runes first var testCases = []struct { rSub map[rune]string sSub map[string]string in string want string }{ {map[rune]string{'o': "left"}, map[string]string{"o": "right"}, "o o", "left-left"}, {map[rune]string{'o': "left", 'a': "r"}, map[string]string{"o": "right"}, "o a o", "left-r-left"}, {map[rune]string{'o': "left"}, map[string]string{"o": "right", "a": "r"}, "a o a o", "r-left-r-left"}, {map[rune]string{'&': "down"}, map[string]string{"&": "up"}, "&", "down"}, } for index, smsot := range testCases { CustomRuneSub = smsot.rSub CustomSub = smsot.sSub got := Make(smsot.in) if got != smsot.want { t.Errorf( "%d. %#v; %#v; Make(%#v) = %#v; want %#v", index, smsot.rSub, smsot.sSub, smsot.in, got, smsot.want) } } } func TestSubstituteLang(t *testing.T) { var testCases = []struct { cSub map[string]string in string want string }{ {map[string]string{"o": "no"}, "o o o", "no no no"}, {map[string]string{"o": "no", "a": "or"}, "o a o", "no nor no"}, {map[string]string{"a": "or", "o": "no"}, "o a o", "no nor no"}, {map[string]string{"'": " "}, "That's great", "That s great"}, } for index, sst := range testCases { got := Substitute(sst.in, sst.cSub) if got != sst.want { t.Errorf( "%d. Substitute(%#v, %#v) = %#v; want %#v", index, sst.in, sst.cSub, got, sst.want) } } } func TestSubstituteRuneLang(t *testing.T) { var testCases = []struct { cSub map[rune]string in string want string }{ {map[rune]string{'o': "no"}, "o o o", "no no no"}, {map[rune]string{'o': "no", 'a': "or"}, "o a o", "no or no"}, {map[rune]string{'a': "or", 'o': "no"}, "o a o", "no or no"}, {map[rune]string{'\'': " "}, "That's great", "That s great"}, } for index, ssrt := range testCases { got := SubstituteRune(ssrt.in, ssrt.cSub) if got != ssrt.want { t.Errorf( "%d. SubstituteRune(%#v, %#v) = %#v; want %#v", index, ssrt.in, ssrt.cSub, got, ssrt.want) } } } func TestSlugMakeSmartTruncate(t *testing.T) { var testCases = []struct { in string maxLength int want string }{ {"DOBROSLAWZYBORT", 100, "dobroslawzybort"}, {"Dobroslaw Zybort", 100, "dobroslaw-zybort"}, {"Dobroslaw Zybort", 12, "dobroslaw"}, {" Dobroslaw Zybort ?", 12, "dobroslaw"}, {"Ala ma 6 kotów.", 10, "ala-ma-6"}, {"Dobrosław Żybort", 5, "dobro"}, } for index, smstt := range testCases { MaxLength = smstt.maxLength got := Make(smstt.in) if got != smstt.want { t.Errorf( "%d. MaxLength = %v; Make(%#v) = %#v; want %#v", index, smstt.maxLength, smstt.in, got, smstt.want) } } } func TestIsSlug(t *testing.T) { MaxLength = 0 type args struct { text string } tests := []struct { name string args args want bool }{ {"some", args{"some"}, true}, {"with -", args{"some-more"}, true}, {"with _", args{"some_more"}, true}, {"with numbers", args{"number-2"}, true}, {"empty string", args{""}, false}, {"upper case", args{"Some-more"}, false}, {"space", args{"some more"}, false}, {"starts with '-'", args{"-some"}, false}, {"ends with '-'", args{"some-"}, false}, {"starts with '_'", args{"_some"}, false}, {"ends with '_'", args{"some_"}, false}, {"outside ASCII", args{"Dobrosław Żybort"}, false}, {"outside ASCII –", args{"2000–2013"}, false}, {"smile ☺", args{"smile ☺"}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := IsSlug(tt.args.text); got != tt.want { t.Errorf("IsSlug() = %v, want %v", got, tt.want) } }) } t.Run("MaxLength", func(t *testing.T) { MaxLength = 4 if got := IsSlug("012345"); got != false { t.Errorf("IsSlug() = %v, want %v", got, false) } MaxLength = 0 }) } func BenchmarkMakeShortAscii(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { Make("Hello world") } } func BenchmarkMakeShort(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { Make("хелло ворлд") } } func BenchmarkMakeShortSymbols(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { Make("·/,:;`˜'\" &€£¥") } } func BenchmarkMakeMediumAscii(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { Make("ABCDE FGHIJ KLMNO PQRST UWXYZ ABCDE FGHIJ KLMNO PQRST UWXYZ ABCDE") } } func BenchmarkMakeMedium(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { Make("ヲァィゥェ ォャュョッ ーアイウエ オカキクケ コサシスセ ソタチツテ トナニヌネ ノハヒフヘ ホマミムメ モヤユヨラ リルレロワ") } } func BenchmarkMakeLongAscii(b *testing.B) { longStr := "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi " + "pulvinar sodales ultrices. Nulla facilisi. Sed at vestibulum erat. Ut " + "sit amet urna posuere, sagittis eros ac, varius nisi. Morbi ullamcorper " + "odio at nunc pulvinar mattis. Vestibulum rutrum, ante eu dictum mattis, " + "elit risus finibus nunc, consectetur facilisis eros leo ut sapien. Sed " + "pulvinar volutpat mi. Cras semper mi ac eros accumsan, at feugiat massa " + "elementum. Morbi eget dolor sit amet purus condimentum egestas non ut " + "sapien. Duis feugiat magna vitae nisi lobortis, quis finibus sem " + "sollicitudin. Pellentesque eleifend blandit ipsum, ut porta arcu " + "ultricies et. Fusce vel ipsum porta, placerat diam ac, consectetur " + "magna. Nulla in porta sem. Suspendisse commodo, felis in molestie " + "ultricies, arcu ipsum aliquet turpis, elementum dapibus ipsum lorem a " + "nisl. Etiam varius imperdiet placerat. Aliquam euismod lacus arcu, " + "ultrices hendrerit est pellentesque vel. Aliquam sit amet laoreet leo. " + "Integer eros libero, mollis sed posuere." b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { Make(longStr) } } func BenchmarkSubstituteRuneShort(b *testing.B) { shortStr := "Hello/Hi world" subs := map[rune]string{'o': "no", '/': "slash"} b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { SubstituteRune(shortStr, subs) } } func BenchmarkSubstituteRuneLong(b *testing.B) { longStr := "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi " + "pulvinar sodales ultrices. Nulla facilisi. Sed at vestibulum erat. Ut " + "sit amet urna posuere, sagittis eros ac, varius nisi. Morbi ullamcorper " + "odio at nunc pulvinar mattis. Vestibulum rutrum, ante eu dictum mattis, " + "elit risus finibus nunc, consectetur facilisis eros leo ut sapien. Sed " + "pulvinar volutpat mi. Cras semper mi ac eros accumsan, at feugiat massa " + "elementum. Morbi eget dolor sit amet purus condimentum egestas non ut " + "sapien. Duis feugiat magna vitae nisi lobortis, quis finibus sem " + "sollicitudin. Pellentesque eleifend blandit ipsum, ut porta arcu " + "ultricies et. Fusce vel ipsum porta, placerat diam ac, consectetur " + "magna. Nulla in porta sem. Suspendisse commodo, felis in molestie " + "ultricies, arcu ipsum aliquet turpis, elementum dapibus ipsum lorem a " + "nisl. Etiam varius imperdiet placerat. Aliquam euismod lacus arcu, " + "ultrices hendrerit est pellentesque vel. Aliquam sit amet laoreet leo. " + "Integer eros libero, mollis sed posuere." subs := map[rune]string{ 'o': "no", '/': "slash", 'i': "done", 'E': "es", 'a': "ASD", '1': "one", 'l': "onetwo", } b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { SubstituteRune(longStr, subs) } } func BenchmarkSmartTruncateShort(b *testing.B) { shortStr := "Hello-world" MaxLength = 8 b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { smartTruncate(shortStr) } } func BenchmarkSmartTruncateLong(b *testing.B) { longStr := "Lorem-ipsum-dolor-sit-amet,-consectetur-adipiscing-elit.-Morbi-" + "pulvinar-sodales-ultrices.-Nulla-facilisi.-Sed-at-vestibulum-erat.-Ut-" + "sit-amet-urna-posuere,-sagittis-eros-ac,-varius-nisi.-Morbi-ullamcorper-" + "odio-at-nunc-pulvinar-mattis.-Vestibulum-rutrum,-ante-eu-dictum-mattis,-" + "elit-risus-finibus-nunc,-consectetur-facilisis-eros-leo-ut-sapien.-Sed-" + "pulvinar-volutpat-mi.-Cras-semper-mi-ac-eros-accumsan,-at-feugiat-massa-" + "elementum.-Morbi-eget-dolor-sit-amet-purus-condimentum-egestas-non-ut-" + "sapien.-Duis-feugiat-magna-vitae-nisi-lobortis,-quis-finibus-sem-" + "sollicitudin.-Pellentesque-eleifend-blandit-ipsum,-ut-porta-arcu-" + "ultricies-et.-Fusce-vel-ipsum-porta,-placerat-diam-ac,-consectetur-" + "magna.-Nulla-in-porta-sem.-Suspendisse-commodo,-felis-in-molestie-" + "ultricies,-arcu-ipsum-aliquet-turpis,-elementum-dapibus-ipsum-lorem-a-" + "nisl.-Etiam-varius-imperdiet-placerat.-Aliquam-euismod-lacus-arcu,-" + "ultrices-hendrerit-est-pellentesque-vel.-Aliquam-sit-amet-laoreet-leo.-" + "Integer-eros-libero,-mollis-sed-posuere." MaxLength = 256 b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { smartTruncate(longStr) } } func BenchmarkIsSlugShort(b *testing.B) { shortStr := "hello-world" b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { IsSlug(shortStr) } } func BenchmarkIsSlugLong(b *testing.B) { longStr := "lorem-ipsum-dolor-sit-amet-consectetur-adipiscing-elit-morbi-" + "pulvinar-sodales-ultrices-nulla-facilisi-sed-at-vestibulum-erat-ut-" + "sit-amet-urna-posuere-sagittis-eros-ac-varius-nisi-morbi-ullamcorper-" + "odio-at-nunc-pulvinar-mattis-vestibulum-rutrum-ante-eu-dictum-mattis,-" + "elit-risus-finibus-nunc-consectetur-facilisis-eros-leo-ut-sapien-sed-" + "pulvinar-volutpat-mi-cras-semper-mi-ac-eros-accumsan-at-feugiat-massa-" + "elementum-morbi-eget-dolor-sit-amet-purus-condimentum-egestas-non-ut-" + "sapien-duis-feugiat-magna-vitae-nisi-lobortis-quis-finibus-sem-" + "sollicitudin-pellentesque-eleifend-blandit-ipsum-ut-porta-arcu-" + "ultricies-et-fusce-vel-ipsum-porta-placerat-diam-ac-consectetur-" + "magna-nulla-in-porta-sem-suspendisse-commodo-felis-in-molestie-" + "ultricies-arcu-ipsum-aliquet-turpis-elementum-dapibus-ipsum-lorem-a-" + "nisl-etiam-varius-imperdiet-placerat-aliquam-euismod-lacus-arcu-" + "ultrices-hendrerit-est-pellentesque-vel-aliquam-sit-amet-laoreet-leo-" + "integer-eros-libero-mollis-sed-posuere" b.ReportAllocs() b.ResetTimer() for n := 0; n < b.N; n++ { IsSlug(longStr) } }