1 題目
Exercise 11.1 Write tests for the charcount program in Section 4.3
2 實現
2.1 改造源代碼
原代碼是一個main包,改造成函數:
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 97.
//!+
// Charcount computes counts of Unicode characters.
package main
import (
"bufio"
"fmt"
"io"
"os"
"unicode"
"unicode/utf8"
)
func main() {
counts, utflen, invalid := charcount(os.Stdin)
fmt.Printf("rune\tcount\n")
for c, n := range counts {
fmt.Printf("%q\t%d\n", c, n)
}
fmt.Print("\nlen\tcount\n")
for i, n := range utflen {
if i > 0 {
fmt.Printf("%d\t%d\n", i, n)
}
}
if invalid > 0 {
fmt.Printf("\n%d invalid UTF-8 characters\n", invalid)
}
}
// counts: counts of Unicode characters
// utflen: count of lengths of UTF-8 encodings
// invalid: count of invalid UTF-8 characters
func charcount(reader io.Reader) (counts map[rune]int, utflen []int, invalid int) {
counts = make(map[rune]int) // counts of Unicode characters
utflen = make([]int, utf8.UTFMax+1) // count of lengths of UTF-8 encodings
invalid = 0 // count of invalid UTF-8 characters
in := bufio.NewReader(reader)
for {
r, n, err := in.ReadRune() // returns rune, nbytes, error
if err == io.EOF {
break
}
if err != nil {
fmt.Fprintf(os.Stderr, "charcount: %v\n", err)
os.Exit(1)
}
if r == unicode.ReplacementChar && n == 1 {
invalid++
continue
}
counts[r]++
utflen[n]++
}
return
}
//!-
2.2 編寫測試用例
package main
import (
"bytes"
"testing"
)
func TestCharCount(t *testing.T) {
str := &bytes.Buffer{}
str.WriteString("hello 世界")
counts, utflen, invalid := charcount(str)
countsWant := map[rune]int{
'h': 1,
'e': 1,
'l': 2,
'o': 1,
'世': 1,
'界': 1,
' ': 1,
}
utflenWant := []int{0, 6, 0, 2, 0}
invalidWant := 0
if invalid != invalidWant {
t.Errorf("invalid count = %v, want %v", invalid, invalidWant)
}
for c, n := range countsWant {
if got, ok := counts[c]; !ok || got != n {
t.Errorf("counts = %v, want %v", counts, countsWant)
}
}
if len(utflenWant) != len(utflen) {
t.Errorf("utflen = %v, want %v", utflen, utflenWant)
}
for i := range utflenWant {
if utflen[i] != utflenWant[i] {
t.Errorf("utflen = %v, want %v", utflen, utflenWant)
break
}
}
}