slug_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Copyright 2013 by Dobrosław Żybort. All rights reserved.
  2. // This Source Code Form is subject to the terms of the Mozilla Public
  3. // License, v. 2.0. If a copy of the MPL was not distributed with this
  4. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  5. package slug
  6. import (
  7. "testing"
  8. )
  9. //=============================================================================
  10. func TestSlugMake(t *testing.T) {
  11. var testCases = []struct {
  12. in string
  13. want string
  14. }{
  15. {"DOBROSLAWZYBORT", "dobroslawzybort"},
  16. {"Dobroslaw Zybort", "dobroslaw-zybort"},
  17. {" Dobroslaw Zybort ?", "dobroslaw-zybort"},
  18. {"Dobrosław Żybort", "dobroslaw-zybort"},
  19. {"Ala ma 6 kotów.", "ala-ma-6-kotow"},
  20. {"áÁàÀãÃâÂäÄąĄą̊Ą̊", "aaaaaaaaaaaaaa"},
  21. {"ćĆĉĈçÇ", "cccccc"},
  22. {"éÉèÈẽẼêÊëËęĘ", "eeeeeeeeeeee"},
  23. {"íÍìÌĩĨîÎïÏįĮ", "iiiiiiiiiiii"},
  24. {"łŁ", "ll"},
  25. {"ńŃ", "nn"},
  26. {"óÓòÒõÕôÔöÖǫǪǭǬø", "ooooooooooooooo"},
  27. {"śŚ", "ss"},
  28. {"úÚùÙũŨûÛüÜųŲ", "uuuuuuuuuuuu"},
  29. {"y̨Y̨", "yy"},
  30. {"źŹżŹ", "zzzz"},
  31. {"·/,:;`˜'\"", ""},
  32. {"2000–2013", "2000-2013"},
  33. {"style—not", "style-not"},
  34. {"test_slug", "test_slug"},
  35. {"Æ", "ae"},
  36. {"Ich heiße", "ich-heisse"},
  37. {"This & that", "this-and-that"},
  38. {"fácil €", "facil-eu"},
  39. {"smile ☺", "smile"},
  40. {"Hellö Wörld хелло ворлд", "hello-world-khello-vorld"},
  41. {"\"C'est déjà l’été.\"", "cest-deja-lete"},
  42. {"jaja---lol-méméméoo--a", "jaja-lol-mememeoo-a"},
  43. {"影師", "ying-shi"},
  44. }
  45. for index, st := range testCases {
  46. got := Make(st.in)
  47. if got != st.want {
  48. t.Errorf(
  49. "%d. Make(%#v) = %#v; want %#v",
  50. index, st.in, got, st.want)
  51. }
  52. }
  53. }
  54. func TestSlugMakeLang(t *testing.T) {
  55. var testCases = []struct {
  56. lang string
  57. in string
  58. want string
  59. }{
  60. {"en", "This & that", "this-and-that"},
  61. {"de", "This & that", "this-und-that"},
  62. {"pl", "This & that", "this-i-that"},
  63. {"es", "This & that", "this-y-that"},
  64. {"test", "This & that", "this-and-that"}, // unknown lang, fallback to "en"
  65. }
  66. for index, smlt := range testCases {
  67. got := MakeLang(smlt.in, smlt.lang)
  68. if got != smlt.want {
  69. t.Errorf(
  70. "%d. MakeLang(%#v, %#v) = %#v; want %#v",
  71. index, smlt.in, smlt.lang, got, smlt.want)
  72. }
  73. }
  74. }
  75. func TestSlugMakeUserSubstituteLang(t *testing.T) {
  76. var testCases = []struct {
  77. cSub map[string]string
  78. lang string
  79. in string
  80. want string
  81. }{
  82. {map[string]string{"'": " "}, "en", "That's great", "that-s-great"},
  83. {map[string]string{"&": "or"}, "en", "This & that", "this-or-that"}, // by default "&" => "and"
  84. {map[string]string{"&": "or"}, "de", "This & that", "this-or-that"}, // by default "&" => "und"
  85. }
  86. for index, smust := range testCases {
  87. CustomSub = smust.cSub
  88. got := MakeLang(smust.in, smust.lang)
  89. if got != smust.want {
  90. t.Errorf(
  91. "%d. %#v; MakeLang(%#v, %#v) = %#v; want %#v",
  92. index, smust.cSub, smust.in, smust.lang,
  93. got, smust.want)
  94. }
  95. }
  96. }
  97. func TestSlugMakeSubstituteOrderLang(t *testing.T) {
  98. // Always substitute runes first
  99. var testCases = []struct {
  100. rSub map[rune]string
  101. sSub map[string]string
  102. in string
  103. want string
  104. }{
  105. {map[rune]string{'o': "left"}, map[string]string{"o": "right"}, "o o", "left-left"},
  106. {map[rune]string{'&': "down"}, map[string]string{"&": "up"}, "&", "down"},
  107. }
  108. for index, smsot := range testCases {
  109. CustomRuneSub = smsot.rSub
  110. CustomSub = smsot.sSub
  111. got := Make(smsot.in)
  112. if got != smsot.want {
  113. t.Errorf(
  114. "%d. %#v; %#v; Make(%#v) = %#v; want %#v",
  115. index, smsot.rSub, smsot.sSub, smsot.in,
  116. got, smsot.want)
  117. }
  118. }
  119. }
  120. func TestSubstituteLang(t *testing.T) {
  121. var testCases = []struct {
  122. cSub map[string]string
  123. in string
  124. want string
  125. }{
  126. {map[string]string{"o": "no"}, "o o o", "no no no"},
  127. {map[string]string{"'": " "}, "That's great", "That s great"},
  128. }
  129. for index, sst := range testCases {
  130. got := Substitute(sst.in, sst.cSub)
  131. if got != sst.want {
  132. t.Errorf(
  133. "%d. Substitute(%#v, %#v) = %#v; want %#v",
  134. index, sst.in, sst.cSub, got, sst.want)
  135. }
  136. }
  137. }
  138. func TestSubstituteRuneLang(t *testing.T) {
  139. var testCases = []struct {
  140. cSub map[rune]string
  141. in string
  142. want string
  143. }{
  144. {map[rune]string{'o': "no"}, "o o o", "no no no"},
  145. {map[rune]string{'\'': " "}, "That's great", "That s great"},
  146. }
  147. for index, ssrt := range testCases {
  148. got := SubstituteRune(ssrt.in, ssrt.cSub)
  149. if got != ssrt.want {
  150. t.Errorf(
  151. "%d. SubstituteRune(%#v, %#v) = %#v; want %#v",
  152. index, ssrt.in, ssrt.cSub, got, ssrt.want)
  153. }
  154. }
  155. }
  156. func TestSlugMakeSmartTruncate(t *testing.T) {
  157. var testCases = []struct {
  158. in string
  159. maxLength int
  160. want string
  161. }{
  162. {"DOBROSLAWZYBORT", 100, "dobroslawzybort"},
  163. {"Dobroslaw Zybort", 100, "dobroslaw-zybort"},
  164. {"Dobroslaw Zybort", 12, "dobroslaw"},
  165. {" Dobroslaw Zybort ?", 12, "dobroslaw"},
  166. {"Ala ma 6 kotów.", 10, "ala-ma-6"},
  167. {"Dobrosław Żybort", 5, "dobro"},
  168. }
  169. for index, smstt := range testCases {
  170. MaxLength = smstt.maxLength
  171. got := Make(smstt.in)
  172. if got != smstt.want {
  173. t.Errorf(
  174. "%d. MaxLength = %v; Make(%#v) = %#v; want %#v",
  175. index, smstt.maxLength, smstt.in, got, smstt.want)
  176. }
  177. }
  178. }
  179. func BenchmarkMakeShortAscii(b *testing.B) {
  180. b.ReportAllocs()
  181. for n := 0; n < b.N; n++ {
  182. Make("Hello world")
  183. }
  184. }
  185. func BenchmarkMakeShort(b *testing.B) {
  186. b.ReportAllocs()
  187. for n := 0; n < b.N; n++ {
  188. Make("хелло ворлд")
  189. }
  190. }
  191. func BenchmarkMakeShortSymbols(b *testing.B) {
  192. b.ReportAllocs()
  193. for n := 0; n < b.N; n++ {
  194. Make("·/,:;`˜'\" &€£¥")
  195. }
  196. }
  197. func BenchmarkMakeMediumAscii(b *testing.B) {
  198. b.ReportAllocs()
  199. for n := 0; n < b.N; n++ {
  200. Make("ABCDE FGHIJ KLMNO PQRST UWXYZ ABCDE FGHIJ KLMNO PQRST UWXYZ ABCDE")
  201. }
  202. }
  203. func BenchmarkMakeMedium(b *testing.B) {
  204. b.ReportAllocs()
  205. for n := 0; n < b.N; n++ {
  206. Make("ヲァィゥェ ォャュョッ ーアイウエ オカキクケ コサシスセ ソタチツテ トナニヌネ ノハヒフヘ ホマミムメ モヤユヨラ リルレロワ")
  207. }
  208. }
  209. func BenchmarkMakeLongAscii(b *testing.B) {
  210. longStr := "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi " +
  211. "pulvinar sodales ultrices. Nulla facilisi. Sed at vestibulum erat. Ut " +
  212. "sit amet urna posuere, sagittis eros ac, varius nisi. Morbi ullamcorper " +
  213. "odio at nunc pulvinar mattis. Vestibulum rutrum, ante eu dictum mattis, " +
  214. "elit risus finibus nunc, consectetur facilisis eros leo ut sapien. Sed " +
  215. "pulvinar volutpat mi. Cras semper mi ac eros accumsan, at feugiat massa " +
  216. "elementum. Morbi eget dolor sit amet purus condimentum egestas non ut " +
  217. "sapien. Duis feugiat magna vitae nisi lobortis, quis finibus sem " +
  218. "sollicitudin. Pellentesque eleifend blandit ipsum, ut porta arcu " +
  219. "ultricies et. Fusce vel ipsum porta, placerat diam ac, consectetur " +
  220. "magna. Nulla in porta sem. Suspendisse commodo, felis in molestie " +
  221. "ultricies, arcu ipsum aliquet turpis, elementum dapibus ipsum lorem a " +
  222. "nisl. Etiam varius imperdiet placerat. Aliquam euismod lacus arcu, " +
  223. "ultrices hendrerit est pellentesque vel. Aliquam sit amet laoreet leo. " +
  224. "Integer eros libero, mollis sed posuere."
  225. b.ReportAllocs()
  226. b.ResetTimer()
  227. for n := 0; n < b.N; n++ {
  228. Make(longStr)
  229. }
  230. }
  231. func BenchmarkSubstituteRuneShort(b *testing.B) {
  232. shortStr := "Hello/Hi world"
  233. subs := map[rune]string{'o': "no", '/': "slash"}
  234. b.ReportAllocs()
  235. b.ResetTimer()
  236. for n := 0; n < b.N; n++ {
  237. SubstituteRune(shortStr, subs)
  238. }
  239. }
  240. func BenchmarkSubstituteRuneLong(b *testing.B) {
  241. longStr := "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi " +
  242. "pulvinar sodales ultrices. Nulla facilisi. Sed at vestibulum erat. Ut " +
  243. "sit amet urna posuere, sagittis eros ac, varius nisi. Morbi ullamcorper " +
  244. "odio at nunc pulvinar mattis. Vestibulum rutrum, ante eu dictum mattis, " +
  245. "elit risus finibus nunc, consectetur facilisis eros leo ut sapien. Sed " +
  246. "pulvinar volutpat mi. Cras semper mi ac eros accumsan, at feugiat massa " +
  247. "elementum. Morbi eget dolor sit amet purus condimentum egestas non ut " +
  248. "sapien. Duis feugiat magna vitae nisi lobortis, quis finibus sem " +
  249. "sollicitudin. Pellentesque eleifend blandit ipsum, ut porta arcu " +
  250. "ultricies et. Fusce vel ipsum porta, placerat diam ac, consectetur " +
  251. "magna. Nulla in porta sem. Suspendisse commodo, felis in molestie " +
  252. "ultricies, arcu ipsum aliquet turpis, elementum dapibus ipsum lorem a " +
  253. "nisl. Etiam varius imperdiet placerat. Aliquam euismod lacus arcu, " +
  254. "ultrices hendrerit est pellentesque vel. Aliquam sit amet laoreet leo. " +
  255. "Integer eros libero, mollis sed posuere."
  256. subs := map[rune]string{
  257. 'o': "no",
  258. '/': "slash",
  259. 'i': "done",
  260. 'E': "es",
  261. 'a': "ASD",
  262. '1': "one",
  263. 'l': "onetwo",
  264. }
  265. b.ReportAllocs()
  266. b.ResetTimer()
  267. for n := 0; n < b.N; n++ {
  268. SubstituteRune(longStr, subs)
  269. }
  270. }
  271. func BenchmarkSmartTruncateShort(b *testing.B) {
  272. shortStr := "Hello-world"
  273. MaxLength = 8
  274. b.ReportAllocs()
  275. b.ResetTimer()
  276. for n := 0; n < b.N; n++ {
  277. smartTruncate(shortStr)
  278. }
  279. }
  280. func BenchmarkSmartTruncateLong(b *testing.B) {
  281. longStr := "Lorem-ipsum-dolor-sit-amet,-consectetur-adipiscing-elit.-Morbi-" +
  282. "pulvinar-sodales-ultrices.-Nulla-facilisi.-Sed-at-vestibulum-erat.-Ut-" +
  283. "sit-amet-urna-posuere,-sagittis-eros-ac,-varius-nisi.-Morbi-ullamcorper-" +
  284. "odio-at-nunc-pulvinar-mattis.-Vestibulum-rutrum,-ante-eu-dictum-mattis,-" +
  285. "elit-risus-finibus-nunc,-consectetur-facilisis-eros-leo-ut-sapien.-Sed-" +
  286. "pulvinar-volutpat-mi.-Cras-semper-mi-ac-eros-accumsan,-at-feugiat-massa-" +
  287. "elementum.-Morbi-eget-dolor-sit-amet-purus-condimentum-egestas-non-ut-" +
  288. "sapien.-Duis-feugiat-magna-vitae-nisi-lobortis,-quis-finibus-sem-" +
  289. "sollicitudin.-Pellentesque-eleifend-blandit-ipsum,-ut-porta-arcu-" +
  290. "ultricies-et.-Fusce-vel-ipsum-porta,-placerat-diam-ac,-consectetur-" +
  291. "magna.-Nulla-in-porta-sem.-Suspendisse-commodo,-felis-in-molestie-" +
  292. "ultricies,-arcu-ipsum-aliquet-turpis,-elementum-dapibus-ipsum-lorem-a-" +
  293. "nisl.-Etiam-varius-imperdiet-placerat.-Aliquam-euismod-lacus-arcu,-" +
  294. "ultrices-hendrerit-est-pellentesque-vel.-Aliquam-sit-amet-laoreet-leo.-" +
  295. "Integer-eros-libero,-mollis-sed-posuere."
  296. MaxLength = 256
  297. b.ReportAllocs()
  298. b.ResetTimer()
  299. for n := 0; n < b.N; n++ {
  300. smartTruncate(longStr)
  301. }
  302. }