Go
Challenge 3 - Test and benchmark
Write a test and benchmark for a function.
Challenge: tests and benchmarks
You will write a slug function, verify it with a table test and compare two implementations with a benchmark. Rules: lower-case it, convert Turkish letters to their ASCII counterparts (ç→c, ğ→g, ı→i, ö→o, ş→s, ü→u), turn everything that isn't a letter or digit into a single dash, and drop leading and trailing dashes.
Slug("Merhaba Dünya!") // merhaba-dunya
Slug(" Go ile Web ") // go-ile-web
Slug("Çay & Şeker") // cay-seker
Plan
Walk the runes with a strings.Builder: map Turkish letters with a map[rune]rune and apply unicode.ToLower; append if it's a letter/digit, otherwise append a dash unless the last appended character was a dash. Finish with strings.Trim(s, "-"). Run the table test in main with an anonymous struct slice; measure allocations with testing.AllocsPerRun.
Exercise Slug and its test
Write the Slug function and try the three cases above with a table test. Print the number of passing cases.
Show example solution
package main
import (
"fmt"
"strings"
"unicode"
)
var trHarf = map[rune]rune{'ç': 'c', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u', 'Ç': 'c', 'Ğ': 'g', 'İ': 'i', 'Ö': 'o', 'Ş': 's', 'Ü': 'u'}
func Slug(s string) string {
var b strings.Builder
tire := false
for _, r := range s {
if t, ok := trHarf[r]; ok {
r = t
}
r = unicode.ToLower(r)
if unicode.IsLetter(r) || unicode.IsDigit(r) {
b.WriteRune(r)
tire = false
} else if !tire {
b.WriteByte('-')
tire = true
}
}
return strings.Trim(b.String(), "-")
}
func main() {
tests := []struct{ in, want string }{
{"Merhaba Dünya!", "merhaba-dunya"},
{" Go ile Web ", "go-ile-web"},
{"Çay & Şeker", "cay-seker"},
}
gecen := 0
for _, tt := range tests {
if Slug(tt.in) == tt.want {
gecen++
}
}
fmt.Println(gecen)
}
Test yourself
-
Why does <code>strings.ToLower("İ")</code> need care?
- It doesn't change
- It becomes ı
- Turkish İ lowercases to "i" plus a combining dot (i̇)
- It errors
Show answer
Turkish İ lowercases to "i" plus a combining dot (i̇) — Under the default Unicode rule İ (U+0130) becomes "i̇"; for Turkish rules use unicode.TurkishCase or a manual mapping.
-
Is it a letter?
if unicode.____(r) || unicode.IsDigit(r) {
b.WriteRune(r)
}
Show answer
if unicode.IsLetter(r) || unicode.IsDigit(r) {
b.WriteRune(r)
}
-
Input and slug
- "Merhaba Dünya!"
- merhaba-dunya
- " Go ile Web "
- go-ile-web
- "Çay & Şeker"
- cay-seker
- "--A--"
- a
Next lesson: Challenge 4 - CLI tool