Commit 6b772462 authored by Rob Pike's avatar Rob Pike

panics: use the new facilities of testing.B instead

Lots of panics go away.
Also fix a name error in html/template.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5498045
parent b9697d4a
...@@ -289,8 +289,7 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) { ...@@ -289,8 +289,7 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
j := index(buf, 'x') j := index(buf, 'x')
if j != n-1 { if j != n-1 {
println("bad index", j) b.Fatal("bad index", j)
panic("bad index")
} }
} }
buf[n-1] = '\x00' buf[n-1] = '\x00'
...@@ -317,7 +316,7 @@ func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) { ...@@ -317,7 +316,7 @@ func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
eq := equal(buf1, buf2) eq := equal(buf1, buf2)
if !eq { if !eq {
panic("bad equal") b.Fatal("bad equal")
} }
} }
buf1[n-1] = '\x00' buf1[n-1] = '\x00'
...@@ -339,8 +338,7 @@ func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) { ...@@ -339,8 +338,7 @@ func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
j := index(buf, buf[n-7:]) j := index(buf, buf[n-7:])
if j != n-7 { if j != n-7 {
println("bad index", j) b.Fatal("bad index", j)
panic("bad index")
} }
} }
buf[n-1] = '\x00' buf[n-1] = '\x00'
...@@ -362,8 +360,7 @@ func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) { ...@@ -362,8 +360,7 @@ func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
j := index(buf, buf[n-7:]) j := index(buf, buf[n-7:])
if j != n-7 { if j != n-7 {
println("bad index", j) b.Fatal("bad index", j)
panic("bad index")
} }
} }
buf[n-1] = '\x00' buf[n-1] = '\x00'
...@@ -385,8 +382,7 @@ func bmCount(b *testing.B, count func([]byte, []byte) int, n int) { ...@@ -385,8 +382,7 @@ func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
j := count(buf, buf[n-7:]) j := count(buf, buf[n-7:])
if j != 1 { if j != 1 {
println("bad count", j) b.Fatal("bad count", j)
panic("bad count")
} }
} }
buf[n-1] = '\x00' buf[n-1] = '\x00'
...@@ -408,8 +404,7 @@ func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) { ...@@ -408,8 +404,7 @@ func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
j := count(buf, buf[n-7:]) j := count(buf, buf[n-7:])
if j != 1 { if j != 1 {
println("bad count", j) b.Fatal("bad count", j)
panic("bad count")
} }
} }
buf[n-1] = '\x00' buf[n-1] = '\x00'
......
...@@ -356,7 +356,7 @@ func BenchmarkEncrypt(b *testing.B) { ...@@ -356,7 +356,7 @@ func BenchmarkEncrypt(b *testing.B) {
tt := encryptTests[0] tt := encryptTests[0]
c, err := NewCipher(tt.key) c, err := NewCipher(tt.key)
if err != nil { if err != nil {
panic("NewCipher") b.Fatal("NewCipher:", err)
} }
out := make([]byte, len(tt.in)) out := make([]byte, len(tt.in))
b.StartTimer() b.StartTimer()
......
...@@ -197,7 +197,7 @@ func BenchmarkReadStruct(b *testing.B) { ...@@ -197,7 +197,7 @@ func BenchmarkReadStruct(b *testing.B) {
} }
b.StopTimer() b.StopTimer()
if !reflect.DeepEqual(s, t) { if !reflect.DeepEqual(s, t) {
panic("no match") b.Fatal("no match")
} }
} }
...@@ -251,6 +251,6 @@ func BenchmarkWriteInts(b *testing.B) { ...@@ -251,6 +251,6 @@ func BenchmarkWriteInts(b *testing.B) {
} }
b.StopTimer() b.StopTimer()
if !bytes.Equal(buf.Bytes(), big[:30]) { if !bytes.Equal(buf.Bytes(), big[:30]) {
panic("first half doesn't match") b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
} }
} }
...@@ -39,7 +39,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) { ...@@ -39,7 +39,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
func BenchmarkEndToEndPipe(b *testing.B) { func BenchmarkEndToEndPipe(b *testing.B) {
r, w, err := os.Pipe() r, w, err := os.Pipe()
if err != nil { if err != nil {
panic("can't get pipe:" + err.Error()) b.Fatal("can't get pipe:", err)
} }
benchmarkEndToEnd(r, w, b) benchmarkEndToEnd(r, w, b)
} }
......
...@@ -84,7 +84,7 @@ func BenchmarkCodeEncoder(b *testing.B) { ...@@ -84,7 +84,7 @@ func BenchmarkCodeEncoder(b *testing.B) {
enc := NewEncoder(ioutil.Discard) enc := NewEncoder(ioutil.Discard)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if err := enc.Encode(&codeStruct); err != nil { if err := enc.Encode(&codeStruct); err != nil {
panic(err) b.Fatal("Encode:", err)
} }
} }
b.SetBytes(int64(len(codeJSON))) b.SetBytes(int64(len(codeJSON)))
...@@ -98,7 +98,7 @@ func BenchmarkCodeMarshal(b *testing.B) { ...@@ -98,7 +98,7 @@ func BenchmarkCodeMarshal(b *testing.B) {
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if _, err := Marshal(&codeStruct); err != nil { if _, err := Marshal(&codeStruct); err != nil {
panic(err) b.Fatal("Marshal:", err)
} }
} }
b.SetBytes(int64(len(codeJSON))) b.SetBytes(int64(len(codeJSON)))
...@@ -120,7 +120,7 @@ func BenchmarkCodeDecoder(b *testing.B) { ...@@ -120,7 +120,7 @@ func BenchmarkCodeDecoder(b *testing.B) {
buf.WriteByte('\n') buf.WriteByte('\n')
buf.WriteByte('\n') buf.WriteByte('\n')
if err := dec.Decode(&r); err != nil { if err := dec.Decode(&r); err != nil {
panic(err) b.Fatal("Decode:", err)
} }
} }
b.SetBytes(int64(len(codeJSON))) b.SetBytes(int64(len(codeJSON)))
...@@ -135,7 +135,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) { ...@@ -135,7 +135,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
var r codeResponse var r codeResponse
if err := Unmarshal(codeJSON, &r); err != nil { if err := Unmarshal(codeJSON, &r); err != nil {
panic(err) b.Fatal("Unmmarshal:", err)
} }
} }
b.SetBytes(int64(len(codeJSON))) b.SetBytes(int64(len(codeJSON)))
...@@ -150,7 +150,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) { ...@@ -150,7 +150,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
var r codeResponse var r codeResponse
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if err := Unmarshal(codeJSON, &r); err != nil { if err := Unmarshal(codeJSON, &r); err != nil {
panic(err) b.Fatal("Unmmarshal:", err)
} }
} }
b.SetBytes(int64(len(codeJSON))) b.SetBytes(int64(len(codeJSON)))
......
...@@ -183,11 +183,11 @@ const ( ...@@ -183,11 +183,11 @@ const (
func (e *Error) Error() string { func (e *Error) Error() string {
if e.Line != 0 { if e.Line != 0 {
return fmt.Sprintf("exp/template/html:%s:%d: %s", e.Name, e.Line, e.Description) return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
} else if e.Name != "" { } else if e.Name != "" {
return fmt.Sprintf("exp/template/html:%s: %s", e.Name, e.Description) return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
} }
return "exp/template/html: " + e.Description return "html/template: " + e.Description
} }
// errorf creates an error given a format string f and args. // errorf creates an error given a format string f and args.
......
...@@ -944,23 +944,23 @@ func TestErrors(t *testing.T) { ...@@ -944,23 +944,23 @@ func TestErrors(t *testing.T) {
}, },
{ {
`<input type=button value=onclick=>`, `<input type=button value=onclick=>`,
`exp/template/html:z: "=" in unquoted attr: "onclick="`, `html/template:z: "=" in unquoted attr: "onclick="`,
}, },
{ {
`<input type=button value= onclick=>`, `<input type=button value= onclick=>`,
`exp/template/html:z: "=" in unquoted attr: "onclick="`, `html/template:z: "=" in unquoted attr: "onclick="`,
}, },
{ {
`<input type=button value= 1+1=2>`, `<input type=button value= 1+1=2>`,
`exp/template/html:z: "=" in unquoted attr: "1+1=2"`, `html/template:z: "=" in unquoted attr: "1+1=2"`,
}, },
{ {
"<a class=`foo>", "<a class=`foo>",
"exp/template/html:z: \"`\" in unquoted attr: \"`foo\"", "html/template:z: \"`\" in unquoted attr: \"`foo\"",
}, },
{ {
`<a style=font:'Arial'>`, `<a style=font:'Arial'>`,
`exp/template/html:z: "'" in unquoted attr: "font:'Arial'"`, `html/template:z: "'" in unquoted attr: "font:'Arial'"`,
}, },
{ {
`<a=foo>`, `<a=foo>`,
......
...@@ -51,7 +51,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) { ...@@ -51,7 +51,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
} }
dst = dst1 dst = dst1
default: default:
panic("unreachable") b.Fatal("unknown destination color model", dcm)
} }
var src image.Image var src image.Image
...@@ -116,7 +116,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) { ...@@ -116,7 +116,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
Rect: image.Rect(0, 0, srcw, srch), Rect: image.Rect(0, 0, srcw, srch),
} }
default: default:
panic("unreachable") b.Fatal("unknown source color model", scm)
} }
var mask image.Image var mask image.Image
...@@ -137,7 +137,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) { ...@@ -137,7 +137,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
} }
mask = mask1 mask = mask1
default: default:
panic("unreachable") b.Fatal("unknown mask color model", mcm)
} }
b.StartTimer() b.StartTimer()
......
...@@ -105,7 +105,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) { ...@@ -105,7 +105,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
} }
} }
if !img.Opaque() { if !img.Opaque() {
panic("expected image to be opaque") b.Fatal("expected image to be opaque")
} }
b.SetBytes(640 * 480 * 4) b.SetBytes(640 * 480 * 4)
b.StartTimer() b.StartTimer()
......
...@@ -125,7 +125,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) { ...@@ -125,7 +125,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
} }
} }
if !img.Opaque() { if !img.Opaque() {
panic("expected image to be opaque") b.Fatal("expected image to be opaque")
} }
b.SetBytes(640 * 480 * 4) b.SetBytes(640 * 480 * 4)
b.StartTimer() b.StartTimer()
...@@ -138,7 +138,7 @@ func BenchmarkEncodeRGBA(b *testing.B) { ...@@ -138,7 +138,7 @@ func BenchmarkEncodeRGBA(b *testing.B) {
b.StopTimer() b.StopTimer()
img := image.NewRGBA(image.Rect(0, 0, 640, 480)) img := image.NewRGBA(image.Rect(0, 0, 640, 480))
if img.Opaque() { if img.Opaque() {
panic("expected image to not be opaque") b.Fatal("expected image to not be opaque")
} }
b.SetBytes(640 * 480 * 4) b.SetBytes(640 * 480 * 4)
b.StartTimer() b.StartTimer()
......
...@@ -113,7 +113,7 @@ func BenchmarkDecode(b *testing.B) { ...@@ -113,7 +113,7 @@ func BenchmarkDecode(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := Decode(r) _, err := Decode(r)
if err != nil { if err != nil {
panic(err) b.Fatal("Decode:", err)
} }
} }
} }
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package big package big
import ( import (
"fmt"
"io" "io"
"strings" "strings"
"testing" "testing"
...@@ -402,7 +401,7 @@ func ScanHelper(b *testing.B, base int, x, y Word) { ...@@ -402,7 +401,7 @@ func ScanHelper(b *testing.B, base int, x, y Word) {
var s string var s string
s = z.string(lowercaseDigits[0:base]) s = z.string(lowercaseDigits[0:base])
if t := toString(z, lowercaseDigits[0:base]); t != s { if t := toString(z, lowercaseDigits[0:base]); t != s {
panic(fmt.Sprintf("scanning: got %s; want %s", s, t)) b.Fatalf("scanning: got %s; want %s", s, t)
} }
b.StartTimer() b.StartTimer()
......
...@@ -1164,15 +1164,15 @@ func BenchmarkClientServer(b *testing.B) { ...@@ -1164,15 +1164,15 @@ func BenchmarkClientServer(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
res, err := Get(ts.URL) res, err := Get(ts.URL)
if err != nil { if err != nil {
panic("Get: " + err.Error()) b.Fatal("Get:", err)
} }
all, err := ioutil.ReadAll(res.Body) all, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
panic("ReadAll: " + err.Error()) b.Fatal("ReadAll:", err)
} }
body := string(all) body := string(all)
if body != "Hello world.\n" { if body != "Hello world.\n" {
panic("Got body: " + body) b.Fatal("Got body:", body)
} }
} }
......
...@@ -516,12 +516,10 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) { ...@@ -516,12 +516,10 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
for atomic.AddInt32(&N, -1) >= 0 { for atomic.AddInt32(&N, -1) >= 0 {
err = client.Call("Arith.Add", args, reply) err = client.Call("Arith.Add", args, reply)
if err != nil { if err != nil {
fmt.Printf("Add: expected no error but got string %q", err.Error()) b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
panic("rpc error")
} }
if reply.C != args.A+args.B { if reply.C != args.A+args.B {
fmt.Printf("Add: expected %d got %d", reply.C, args.A+args.B) b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
panic("rpc error")
} }
} }
wg.Done() wg.Done()
...@@ -536,8 +534,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) { ...@@ -536,8 +534,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
once.Do(startServer) once.Do(startServer)
client, err := dial() client, err := dial()
if err != nil { if err != nil {
fmt.Println("error dialing", err) b.Fatalf("error dialing:", err)
return
} }
// Asynchronous calls // Asynchronous calls
...@@ -561,12 +558,11 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) { ...@@ -561,12 +558,11 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
}() }()
go func() { go func() {
for call := range res { for call := range res {
a := call.Args.(*Args).A A := call.Args.(*Args).A
b := call.Args.(*Args).B B := call.Args.(*Args).B
c := call.Reply.(*Reply).C C := call.Reply.(*Reply).C
if a+b != c { if A+B != C {
fmt.Printf("Add: expected %d got %d", a+b, c) b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C)
panic("incorrect reply")
} }
<-gate <-gate
if atomic.AddInt32(&recv, -1) == 0 { if atomic.AddInt32(&recv, -1) == 0 {
......
...@@ -321,8 +321,7 @@ func BenchmarkLiteral(b *testing.B) { ...@@ -321,8 +321,7 @@ func BenchmarkLiteral(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatal("no match!")
break
} }
} }
} }
...@@ -334,8 +333,7 @@ func BenchmarkNotLiteral(b *testing.B) { ...@@ -334,8 +333,7 @@ func BenchmarkNotLiteral(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatal("no match!")
break
} }
} }
} }
...@@ -347,8 +345,7 @@ func BenchmarkMatchClass(b *testing.B) { ...@@ -347,8 +345,7 @@ func BenchmarkMatchClass(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatal("no match!")
break
} }
} }
} }
...@@ -362,8 +359,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) { ...@@ -362,8 +359,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatal("no match!")
break
} }
} }
} }
......
...@@ -324,8 +324,7 @@ func BenchmarkLiteral(b *testing.B) { ...@@ -324,8 +324,7 @@ func BenchmarkLiteral(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatalf("no match!")
break
} }
} }
} }
...@@ -337,8 +336,7 @@ func BenchmarkNotLiteral(b *testing.B) { ...@@ -337,8 +336,7 @@ func BenchmarkNotLiteral(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatalf("no match!")
break
} }
} }
} }
...@@ -350,8 +348,7 @@ func BenchmarkMatchClass(b *testing.B) { ...@@ -350,8 +348,7 @@ func BenchmarkMatchClass(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatalf("no match!")
break
} }
} }
} }
...@@ -365,8 +362,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) { ...@@ -365,8 +362,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) {
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if !re.MatchString(x) { if !re.MatchString(x) {
println("no match!") b.Fatalf("no match!")
break
} }
} }
} }
......
...@@ -673,7 +673,7 @@ func benchmark(b *testing.B, re string, n int) { ...@@ -673,7 +673,7 @@ func benchmark(b *testing.B, re string, n int) {
b.SetBytes(int64(n)) b.SetBytes(int64(n))
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if r.Match(t) { if r.Match(t) {
panic("match!") b.Fatal("match!")
} }
} }
} }
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"bytes" "bytes"
"io" "io"
"reflect" "reflect"
"strconv"
. "strings" . "strings"
"testing" "testing"
"unicode" "unicode"
...@@ -143,7 +142,7 @@ const benchmarkString = "some_text=some☺value" ...@@ -143,7 +142,7 @@ const benchmarkString = "some_text=some☺value"
func BenchmarkIndexRune(b *testing.B) { func BenchmarkIndexRune(b *testing.B) {
if got := IndexRune(benchmarkString, '☺'); got != 14 { if got := IndexRune(benchmarkString, '☺'); got != 14 {
panic("wrong index: got=" + strconv.Itoa(got)) b.Fatalf("wrong index: expected 14, got=%d", got)
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
IndexRune(benchmarkString, '☺') IndexRune(benchmarkString, '☺')
...@@ -152,7 +151,7 @@ func BenchmarkIndexRune(b *testing.B) { ...@@ -152,7 +151,7 @@ func BenchmarkIndexRune(b *testing.B) {
func BenchmarkIndexRuneFastPath(b *testing.B) { func BenchmarkIndexRuneFastPath(b *testing.B) {
if got := IndexRune(benchmarkString, 'v'); got != 17 { if got := IndexRune(benchmarkString, 'v'); got != 17 {
panic("wrong index: got=" + strconv.Itoa(got)) b.Fatalf("wrong index: expected 17, got=%d", got)
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
IndexRune(benchmarkString, 'v') IndexRune(benchmarkString, 'v')
...@@ -161,7 +160,7 @@ func BenchmarkIndexRuneFastPath(b *testing.B) { ...@@ -161,7 +160,7 @@ func BenchmarkIndexRuneFastPath(b *testing.B) {
func BenchmarkIndex(b *testing.B) { func BenchmarkIndex(b *testing.B) {
if got := Index(benchmarkString, "v"); got != 17 { if got := Index(benchmarkString, "v"); got != 17 {
panic("wrong index: got=" + strconv.Itoa(got)) b.Fatalf("wrong index: expected 17, got=%d", got)
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
Index(benchmarkString, "v") Index(benchmarkString, "v")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment