// functions1.go
// To run at the command line:
// $ go run functions1.go
package main
import "fmt"
// returns the first index i such that match(s[i]) is false
// if no character matches, then len(s) is returned
func firstNonMatching(s string, match func(rune) bool) int {
i := 0
for i < len(s) && match(rune(s[i])) {
i++
}
return i
}
func getLongestPrefix(s string, match func(rune) bool) string {
return s[:firstNonMatching(s, match)]
}
func removeLongestPrefix(s string, match func(rune) bool) string {
return s[firstNonMatching(s, match):]
}
func test_getLongestPrefix() {
// This is an example of table-driven testing.
// All the test cases are put in a slice of structs called testcases.
// Each entry in testcases stores the input and expected output.
// The code after the table then calls the function being tested, in
// this case getLongestPrefix, on each entry in test cases, check that
// the the expected output matches the actual output.
//
// Table-driven testing has a couple of nice features. It's automated, so
// you can easily run it after any change to your code. It's also easy to
// add new entires to testcases.
testcases := []struct {
str string
matchFn func(rune) bool
expected string
}{
{"x+y", isLetter, "x"},
{"13 * j", isLetter, ""},
{"13 * j", isDigit, "13"},
{"one two three", isLetter, "one"},
}
failures := 0
for i, test := range testcases {
if actual := getLongestPrefix(test.str, test.matchFn); actual != test.expected {
fmt.Printf("test %v failed:\n", i)
fmt.Printf(" input: \"%v\"\n", test.str)
fmt.Printf(" actual: \"%v\"\n", actual)
fmt.Printf(" expected: \"%v\"\n\n", test.expected)
failures++
}
}
if failures == 0 {
fmt.Println("all tests passed")
} else if failures == 1 {
fmt.Println("1 test case failed")
} else {
fmt.Printf("%v test cases failed\n", failures)
}
} // test_getLongestPrefix
func main() {
test_getLongestPrefix()
}
//
// some character matching functions
//
func isWhitespace(r rune) bool {
return r == ' ' || r == '\n' || r == '\t'
}
func isLower(r rune) bool {
return 'a' <= r && r <= 'z'
}
func isUpper(r rune) bool {
return 'A' <= r && r <= 'Z'
}
func isLetter(r rune) bool {
return isLower(r) || isUpper(r)
}
func isIdentStartChar(r rune) bool {
return r == '_' || isLetter(r)
}
func isDigit(r rune) bool {
return '0' <= r && r <= '9'
}
func isIdentChar(r rune) bool {
return isIdentStartChar(r) || isDigit(r)
}