mirror of
https://github.com/Luzifer/mondash.git
synced 2024-12-24 13:01:19 +00:00
422 lines
13 KiB
Go
422 lines
13 KiB
Go
|
// 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)
|
|||
|
}
|
|||
|
}
|