From b27cd8f5235561704e9bb6d455f3f1fd2ac7ada5 Mon Sep 17 00:00:00 2001 From: Arunesh Dwivedi Date: Tue, 25 Aug 2026 07:42:15 +0000 Subject: [PATCH 1/2] fix: report reformatted failpoint header instead of panicking When gofmt reformats a failpoint header across multiple lines, the type assertion lands on a later line than the 'if'. ToComments would panic with index out of range when trying to extract the type from the header line. Return a descriptive error instead, preventing the crash and the wedged .tmp file that leaves the tool unusable until manually cleaned up. Fixes #158 Signed-off-by: Arunesh Dwivedi --- code/rewrite.go | 6 +- code/rewrite.go.bak | 181 +++++++++++++++++++++++++++++++++++++++ code/rewrite_test.go | 13 +++ code/rewrite_test.go.bak | 126 +++++++++++++++++++++++++++ 4 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 code/rewrite.go.bak create mode 100644 code/rewrite_test.go.bak diff --git a/code/rewrite.go b/code/rewrite.go index fcf53cf..12365a7 100644 --- a/code/rewrite.go +++ b/code/rewrite.go @@ -112,7 +112,11 @@ func ToComments(wdst io.Writer, rsrc io.Reader) ([]*Failpoint, error) { ws = strings.Split(l, "i")[0] n := strings.Split(strings.Split(l, "__fp_")[1], ".")[0] - t := strings.Split(strings.Split(l, ".(")[1], ")")[0] + parts := strings.Split(l, ".(") + if len(parts) < 2 { + return fps, fmt.Errorf("failpoint %q header is missing its type assertion, the generated code may have been reformatted: %q", n, lTrim) + } + t := strings.Split(parts[1], ")")[0] dst.WriteString(ws + pfx + " var " + n + " " + t + "\n") if !strings.Contains(l, "; goto __nomock") { // not single liner diff --git a/code/rewrite.go.bak b/code/rewrite.go.bak new file mode 100644 index 0000000..fcf53cf --- /dev/null +++ b/code/rewrite.go.bak @@ -0,0 +1,181 @@ +// Copyright 2016 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package code + +import ( + "bufio" + "fmt" + "io" + "strings" + "unicode" +) + +const ( + pfxGofail = `// gofail:` + labelGofail = `/* gofail-label */` + errVarGoFail = `__fpErr` +) + +// ToFailpoints turns all gofail comments into failpoint code. Returns a list of +// all failpoints it activated. +func ToFailpoints(wdst io.Writer, rsrc io.Reader) ([]*Failpoint, error) { + var err error + var curfp *Failpoint + var fps []*Failpoint + + dst := bufio.NewWriter(wdst) + defer func() { + if err == nil && curfp != nil { + err = curfp.flush(dst) + } + if err == nil { + err = dst.Flush() + } + }() + + src := bufio.NewReader(rsrc) + for err == nil { + l, rerr := src.ReadString('\n') + if curfp != nil { + if strings.HasPrefix(strings.TrimSpace(l), "//") { + if len(l) > 0 && l[len(l)-1] == '\n' { + l = l[:len(l)-1] + } + curfp.code = append(curfp.code, strings.Replace(l, "//", "\t", 1)) + continue + } + curfp.flush(dst) + fps = append(fps, curfp) + curfp = nil + } else if label := gofailLabel(l, pfxGofail, labelGofail); label != "" { + // expose gofail label + l = label + } else if curfp, err = newFailpoint(l); err != nil { + return nil, err + } else if curfp != nil { + // found a new failpoint + continue + } + if _, err = dst.WriteString(l); err != nil { + return nil, err + } + if rerr == io.EOF { + break + } + } + return fps, err +} + +// ToComments turns all failpoint code into GOFAIL comments. It returns +// a list of all failpoints it deactivated. +func ToComments(wdst io.Writer, rsrc io.Reader) ([]*Failpoint, error) { + var err error + var fps []*Failpoint + + src := bufio.NewReader(rsrc) + dst := bufio.NewWriter(wdst) + ws := "" + unmatchedBraces := 0 + for err == nil { + l, rerr := src.ReadString('\n') + err = rerr + lTrim := strings.TrimSpace(l) + + if unmatchedBraces > 0 { + opening, closing := numBraces(l) + unmatchedBraces += opening - closing + if unmatchedBraces == 0 { + // strip off badType footer + lTrim = strings.Split(lTrim, "; goto __nomock")[0] + } + s := ws + "//" + wsPrefix(l, ws)[1:] + lTrim + "\n" + dst.WriteString(s) + continue + } + + isErrVarGoFail := strings.Contains(l, fmt.Sprintf(", %s := __fp_", errVarGoFail)) + isHdr := isErrVarGoFail && strings.HasPrefix(lTrim, "if") + if isHdr { + pfx := pfxGofail + + ws = strings.Split(l, "i")[0] + n := strings.Split(strings.Split(l, "__fp_")[1], ".")[0] + t := strings.Split(strings.Split(l, ".(")[1], ")")[0] + dst.WriteString(ws + pfx + " var " + n + " " + t + "\n") + if !strings.Contains(l, "; goto __nomock") { + // not single liner + unmatchedBraces = 1 + } + fps = append(fps, &Failpoint{name: n, varType: t}) + continue + } + + if isLabel := strings.Contains(l, "\t"+labelGofail); isLabel { + l = strings.Replace(l, labelGofail, pfxGofail, 1) + } + + if _, werr := dst.WriteString(l); werr != nil { + return fps, werr + } + } + if err == io.EOF { + err = nil + } + dst.Flush() + return fps, err +} + +func gofailLabel(l string, pfx string, lb string) string { + if !strings.HasPrefix(strings.TrimSpace(l), pfx) { + return "" + } + label := strings.SplitAfter(l, pfx)[1] + if len(label) == 0 || !strings.Contains(label, ":") { + return "" + } + return strings.Replace(l, pfx, lb, 1) +} + +func numBraces(l string) (opening int, closing int) { + for i := 0; i < len(l); i++ { + switch l[i] { + case '{': + opening++ + case '}': + closing++ + } + } + return +} + +// wsPrefix computes the left padding of a line given a whitespace prefix. +func wsPrefix(l, wsPfx string) string { + lws := "" + if len(wsPfx) == 0 { + lws = l + } else { + wsSplit := strings.SplitAfter(l, wsPfx) + if len(wsSplit) < 2 { + return "" + } + lws = strings.Join(wsSplit[1:], "") + } + for i, c := range lws { + if !unicode.IsSpace(c) { + return lws[:i] + } + } + return lws +} diff --git a/code/rewrite_test.go b/code/rewrite_test.go index 07dc685..9925e90 100644 --- a/code/rewrite_test.go +++ b/code/rewrite_test.go @@ -124,3 +124,16 @@ func TestToComment(t *testing.T) { require.Equalf(t, len(fps), ex.wfps, "%d: got %d failpoints but expected %d", i, len(fps), ex.wfps) } } + +func TestToCommentsReformattedHeader(t *testing.T) { + // gofmt splits the header across lines: + // if vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { + // Test, __fpTypeOK := vTest.(int); ... + // The second line contains ".(" but not the first, so strings.Split(l, ".(")[1] panics. + reformatted := "if vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil {\n\tTest, __fpTypeOK := vTest.(int)\n\tfmt.Println(Test)\n}\n" + dst := bytes.NewBuffer(nil) + src := strings.NewReader(reformatted) + _, err := ToComments(dst, src) + require.Error(t, err) + require.Contains(t, err.Error(), "type assertion") +} diff --git a/code/rewrite_test.go.bak b/code/rewrite_test.go.bak new file mode 100644 index 0000000..07dc685 --- /dev/null +++ b/code/rewrite_test.go.bak @@ -0,0 +1,126 @@ +// Copyright 2016 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package code + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +var examples = []struct { + code string + expectedGeneratedCode string + wfps int +}{ + { + "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)\n}", + "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}", + 1, + }, + { + "func f() {\n\t\t// gofail: var Test int\n\t\t// \tfmt.Println(Test)\n}", + "func f() {\n\t\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t\t \tfmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}", + 1, + }, + { + "func f() {\n// gofail: var Test int\n// \tfmt.Println(Test)\n}", + "func f() {\nif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t \tfmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}", + 1, + }, + { + "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)\n}\n", + "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}\n", + 1}, + { + "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)// return\n}\n", + "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test)// return; goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}\n", + 1, + }, + { + "func f() {\n\t// gofail: var OneLineTest int\n}\n", + "func f() {\n\tif vOneLineTest, __fpErr := __fp_OneLineTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vOneLineTest.(int); if !__fpTypeOK { goto __badTypeOneLineTest} ; goto __nomockOneLineTest; __badTypeOneLineTest: __fp_OneLineTest.BadType(vOneLineTest, \"int\"); __nomockOneLineTest: };\n}\n", + 1, + }, + { + "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)\n\n\t// gofail: var Test2 int\n\t// fmt.Println(Test2)\n}\n", + "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n\n\tif vTest2, __fpErr := __fp_Test2.Acquire(); __fpErr == nil { Test2, __fpTypeOK := vTest2.(int); if !__fpTypeOK { goto __badTypeTest2} \n\t\t fmt.Println(Test2); goto __nomockTest2; __badTypeTest2: __fp_Test2.BadType(vTest2, \"int\"); __nomockTest2: };\n}\n", + 2, + }, + { + "func f() {\n\t// gofail: var NoTypeTest struct{}\n\t// fmt.Println(`hi`)\n}\n", + "func f() {\n\tif vNoTypeTest, __fpErr := __fp_NoTypeTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vNoTypeTest.(struct{}); if !__fpTypeOK { goto __badTypeNoTypeTest} \n\t\t fmt.Println(`hi`); goto __nomockNoTypeTest; __badTypeNoTypeTest: __fp_NoTypeTest.BadType(vNoTypeTest, \"struct{}\"); __nomockNoTypeTest: };\n}\n", + 1, + }, + { + "func f() {\n\t// gofail: var NoTypeTest struct{}\n}\n", + "func f() {\n\tif vNoTypeTest, __fpErr := __fp_NoTypeTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vNoTypeTest.(struct{}); if !__fpTypeOK { goto __badTypeNoTypeTest} ; goto __nomockNoTypeTest; __badTypeNoTypeTest: __fp_NoTypeTest.BadType(vNoTypeTest, \"struct{}\"); __nomockNoTypeTest: };\n}\n", + 1, + }, + { + "func f() {\n\t// gofail: var NoTypeTest struct{}\n\t// fmt.Println(`hi`)\n\t// fmt.Println(`bye`)\n}\n", + "func f() {\n\tif vNoTypeTest, __fpErr := __fp_NoTypeTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vNoTypeTest.(struct{}); if !__fpTypeOK { goto __badTypeNoTypeTest} \n\t\t fmt.Println(`hi`)\n\t\t fmt.Println(`bye`); goto __nomockNoTypeTest; __badTypeNoTypeTest: __fp_NoTypeTest.BadType(vNoTypeTest, \"struct{}\"); __nomockNoTypeTest: };\n}\n", + 1, + }, + { + ` +func f() { + // gofail: labelTest: + for { + if g() { + // gofail: var testLabel struct{} + // continue labelTest + return + } + } +} +`, + "\nfunc f() {\n\t/* gofail-label */ labelTest:\n\tfor {\n\t\tif g() {\n\t\t\tif vtestLabel, __fpErr := __fp_testLabel.Acquire(); __fpErr == nil { _, __fpTypeOK := vtestLabel.(struct{}); if !__fpTypeOK { goto __badTypetestLabel} \n\t\t\t\t continue labelTest; goto __nomocktestLabel; __badTypetestLabel: __fp_testLabel.BadType(vtestLabel, \"struct{}\"); __nomocktestLabel: };\n\t\t\treturn\n\t\t}\n\t}\n}\n", + 1, + }, +} + +func TestToFailpoint(t *testing.T) { + for i, ex := range examples { + dst := bytes.NewBuffer(make([]byte, 0, 1024)) + src := strings.NewReader(ex.code) + fps, err := ToFailpoints(dst, src) + require.NoErrorf(t, err, "%d: %v", i, err) + require.Equalf(t, len(fps), ex.wfps, "%d: got %d failpoints but expected %d", i, len(fps), ex.wfps) + dstOut := dst.String() + require.Lenf(t, strings.Split(ex.code, "\n"), len(strings.Split(dstOut, "\n")), "%d: bad line count %q", i, dstOut) + require.Equalf(t, ex.expectedGeneratedCode, dstOut, "expected generated code and actual generated code differs:\nExpected:\n%q\n\nActual:\n%q", ex.expectedGeneratedCode, dstOut) + } +} + +func TestToComment(t *testing.T) { + for i, ex := range examples { + dst := bytes.NewBuffer(make([]byte, 0, 1024)) + src := strings.NewReader(ex.code) + _, err := ToFailpoints(dst, src) + require.NoErrorf(t, err, "%d: %v", i, err) + + src = strings.NewReader(dst.String()) + dst.Reset() + fps, err := ToComments(dst, src) + require.NoErrorf(t, err, "unexpected error: %v", err) + plainCode := dst.String() + + require.Equalf(t, plainCode, ex.code, "%d: non-preserving ToComments(); got %q, want %q", i, plainCode, ex.code) + require.Equalf(t, len(fps), ex.wfps, "%d: got %d failpoints but expected %d", i, len(fps), ex.wfps) + } +} From feff108e2e85b4c3ae528075c7902e29ad9dbde4 Mon Sep 17 00:00:00 2001 From: Arunesh Dwivedi Date: Tue, 25 Aug 2026 07:42:35 +0000 Subject: [PATCH 2/2] chore: remove backup files Signed-off-by: Arunesh Dwivedi --- code/rewrite.go.bak | 181 --------------------------------------- code/rewrite_test.go.bak | 126 --------------------------- 2 files changed, 307 deletions(-) delete mode 100644 code/rewrite.go.bak delete mode 100644 code/rewrite_test.go.bak diff --git a/code/rewrite.go.bak b/code/rewrite.go.bak deleted file mode 100644 index fcf53cf..0000000 --- a/code/rewrite.go.bak +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2016 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package code - -import ( - "bufio" - "fmt" - "io" - "strings" - "unicode" -) - -const ( - pfxGofail = `// gofail:` - labelGofail = `/* gofail-label */` - errVarGoFail = `__fpErr` -) - -// ToFailpoints turns all gofail comments into failpoint code. Returns a list of -// all failpoints it activated. -func ToFailpoints(wdst io.Writer, rsrc io.Reader) ([]*Failpoint, error) { - var err error - var curfp *Failpoint - var fps []*Failpoint - - dst := bufio.NewWriter(wdst) - defer func() { - if err == nil && curfp != nil { - err = curfp.flush(dst) - } - if err == nil { - err = dst.Flush() - } - }() - - src := bufio.NewReader(rsrc) - for err == nil { - l, rerr := src.ReadString('\n') - if curfp != nil { - if strings.HasPrefix(strings.TrimSpace(l), "//") { - if len(l) > 0 && l[len(l)-1] == '\n' { - l = l[:len(l)-1] - } - curfp.code = append(curfp.code, strings.Replace(l, "//", "\t", 1)) - continue - } - curfp.flush(dst) - fps = append(fps, curfp) - curfp = nil - } else if label := gofailLabel(l, pfxGofail, labelGofail); label != "" { - // expose gofail label - l = label - } else if curfp, err = newFailpoint(l); err != nil { - return nil, err - } else if curfp != nil { - // found a new failpoint - continue - } - if _, err = dst.WriteString(l); err != nil { - return nil, err - } - if rerr == io.EOF { - break - } - } - return fps, err -} - -// ToComments turns all failpoint code into GOFAIL comments. It returns -// a list of all failpoints it deactivated. -func ToComments(wdst io.Writer, rsrc io.Reader) ([]*Failpoint, error) { - var err error - var fps []*Failpoint - - src := bufio.NewReader(rsrc) - dst := bufio.NewWriter(wdst) - ws := "" - unmatchedBraces := 0 - for err == nil { - l, rerr := src.ReadString('\n') - err = rerr - lTrim := strings.TrimSpace(l) - - if unmatchedBraces > 0 { - opening, closing := numBraces(l) - unmatchedBraces += opening - closing - if unmatchedBraces == 0 { - // strip off badType footer - lTrim = strings.Split(lTrim, "; goto __nomock")[0] - } - s := ws + "//" + wsPrefix(l, ws)[1:] + lTrim + "\n" - dst.WriteString(s) - continue - } - - isErrVarGoFail := strings.Contains(l, fmt.Sprintf(", %s := __fp_", errVarGoFail)) - isHdr := isErrVarGoFail && strings.HasPrefix(lTrim, "if") - if isHdr { - pfx := pfxGofail - - ws = strings.Split(l, "i")[0] - n := strings.Split(strings.Split(l, "__fp_")[1], ".")[0] - t := strings.Split(strings.Split(l, ".(")[1], ")")[0] - dst.WriteString(ws + pfx + " var " + n + " " + t + "\n") - if !strings.Contains(l, "; goto __nomock") { - // not single liner - unmatchedBraces = 1 - } - fps = append(fps, &Failpoint{name: n, varType: t}) - continue - } - - if isLabel := strings.Contains(l, "\t"+labelGofail); isLabel { - l = strings.Replace(l, labelGofail, pfxGofail, 1) - } - - if _, werr := dst.WriteString(l); werr != nil { - return fps, werr - } - } - if err == io.EOF { - err = nil - } - dst.Flush() - return fps, err -} - -func gofailLabel(l string, pfx string, lb string) string { - if !strings.HasPrefix(strings.TrimSpace(l), pfx) { - return "" - } - label := strings.SplitAfter(l, pfx)[1] - if len(label) == 0 || !strings.Contains(label, ":") { - return "" - } - return strings.Replace(l, pfx, lb, 1) -} - -func numBraces(l string) (opening int, closing int) { - for i := 0; i < len(l); i++ { - switch l[i] { - case '{': - opening++ - case '}': - closing++ - } - } - return -} - -// wsPrefix computes the left padding of a line given a whitespace prefix. -func wsPrefix(l, wsPfx string) string { - lws := "" - if len(wsPfx) == 0 { - lws = l - } else { - wsSplit := strings.SplitAfter(l, wsPfx) - if len(wsSplit) < 2 { - return "" - } - lws = strings.Join(wsSplit[1:], "") - } - for i, c := range lws { - if !unicode.IsSpace(c) { - return lws[:i] - } - } - return lws -} diff --git a/code/rewrite_test.go.bak b/code/rewrite_test.go.bak deleted file mode 100644 index 07dc685..0000000 --- a/code/rewrite_test.go.bak +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2016 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package code - -import ( - "bytes" - "strings" - "testing" - - "github.com/stretchr/testify/require" -) - -var examples = []struct { - code string - expectedGeneratedCode string - wfps int -}{ - { - "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)\n}", - "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}", - 1, - }, - { - "func f() {\n\t\t// gofail: var Test int\n\t\t// \tfmt.Println(Test)\n}", - "func f() {\n\t\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t\t \tfmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}", - 1, - }, - { - "func f() {\n// gofail: var Test int\n// \tfmt.Println(Test)\n}", - "func f() {\nif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t \tfmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}", - 1, - }, - { - "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)\n}\n", - "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}\n", - 1}, - { - "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)// return\n}\n", - "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test)// return; goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n}\n", - 1, - }, - { - "func f() {\n\t// gofail: var OneLineTest int\n}\n", - "func f() {\n\tif vOneLineTest, __fpErr := __fp_OneLineTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vOneLineTest.(int); if !__fpTypeOK { goto __badTypeOneLineTest} ; goto __nomockOneLineTest; __badTypeOneLineTest: __fp_OneLineTest.BadType(vOneLineTest, \"int\"); __nomockOneLineTest: };\n}\n", - 1, - }, - { - "func f() {\n\t// gofail: var Test int\n\t// fmt.Println(Test)\n\n\t// gofail: var Test2 int\n\t// fmt.Println(Test2)\n}\n", - "func f() {\n\tif vTest, __fpErr := __fp_Test.Acquire(); __fpErr == nil { Test, __fpTypeOK := vTest.(int); if !__fpTypeOK { goto __badTypeTest} \n\t\t fmt.Println(Test); goto __nomockTest; __badTypeTest: __fp_Test.BadType(vTest, \"int\"); __nomockTest: };\n\n\tif vTest2, __fpErr := __fp_Test2.Acquire(); __fpErr == nil { Test2, __fpTypeOK := vTest2.(int); if !__fpTypeOK { goto __badTypeTest2} \n\t\t fmt.Println(Test2); goto __nomockTest2; __badTypeTest2: __fp_Test2.BadType(vTest2, \"int\"); __nomockTest2: };\n}\n", - 2, - }, - { - "func f() {\n\t// gofail: var NoTypeTest struct{}\n\t// fmt.Println(`hi`)\n}\n", - "func f() {\n\tif vNoTypeTest, __fpErr := __fp_NoTypeTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vNoTypeTest.(struct{}); if !__fpTypeOK { goto __badTypeNoTypeTest} \n\t\t fmt.Println(`hi`); goto __nomockNoTypeTest; __badTypeNoTypeTest: __fp_NoTypeTest.BadType(vNoTypeTest, \"struct{}\"); __nomockNoTypeTest: };\n}\n", - 1, - }, - { - "func f() {\n\t// gofail: var NoTypeTest struct{}\n}\n", - "func f() {\n\tif vNoTypeTest, __fpErr := __fp_NoTypeTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vNoTypeTest.(struct{}); if !__fpTypeOK { goto __badTypeNoTypeTest} ; goto __nomockNoTypeTest; __badTypeNoTypeTest: __fp_NoTypeTest.BadType(vNoTypeTest, \"struct{}\"); __nomockNoTypeTest: };\n}\n", - 1, - }, - { - "func f() {\n\t// gofail: var NoTypeTest struct{}\n\t// fmt.Println(`hi`)\n\t// fmt.Println(`bye`)\n}\n", - "func f() {\n\tif vNoTypeTest, __fpErr := __fp_NoTypeTest.Acquire(); __fpErr == nil { _, __fpTypeOK := vNoTypeTest.(struct{}); if !__fpTypeOK { goto __badTypeNoTypeTest} \n\t\t fmt.Println(`hi`)\n\t\t fmt.Println(`bye`); goto __nomockNoTypeTest; __badTypeNoTypeTest: __fp_NoTypeTest.BadType(vNoTypeTest, \"struct{}\"); __nomockNoTypeTest: };\n}\n", - 1, - }, - { - ` -func f() { - // gofail: labelTest: - for { - if g() { - // gofail: var testLabel struct{} - // continue labelTest - return - } - } -} -`, - "\nfunc f() {\n\t/* gofail-label */ labelTest:\n\tfor {\n\t\tif g() {\n\t\t\tif vtestLabel, __fpErr := __fp_testLabel.Acquire(); __fpErr == nil { _, __fpTypeOK := vtestLabel.(struct{}); if !__fpTypeOK { goto __badTypetestLabel} \n\t\t\t\t continue labelTest; goto __nomocktestLabel; __badTypetestLabel: __fp_testLabel.BadType(vtestLabel, \"struct{}\"); __nomocktestLabel: };\n\t\t\treturn\n\t\t}\n\t}\n}\n", - 1, - }, -} - -func TestToFailpoint(t *testing.T) { - for i, ex := range examples { - dst := bytes.NewBuffer(make([]byte, 0, 1024)) - src := strings.NewReader(ex.code) - fps, err := ToFailpoints(dst, src) - require.NoErrorf(t, err, "%d: %v", i, err) - require.Equalf(t, len(fps), ex.wfps, "%d: got %d failpoints but expected %d", i, len(fps), ex.wfps) - dstOut := dst.String() - require.Lenf(t, strings.Split(ex.code, "\n"), len(strings.Split(dstOut, "\n")), "%d: bad line count %q", i, dstOut) - require.Equalf(t, ex.expectedGeneratedCode, dstOut, "expected generated code and actual generated code differs:\nExpected:\n%q\n\nActual:\n%q", ex.expectedGeneratedCode, dstOut) - } -} - -func TestToComment(t *testing.T) { - for i, ex := range examples { - dst := bytes.NewBuffer(make([]byte, 0, 1024)) - src := strings.NewReader(ex.code) - _, err := ToFailpoints(dst, src) - require.NoErrorf(t, err, "%d: %v", i, err) - - src = strings.NewReader(dst.String()) - dst.Reset() - fps, err := ToComments(dst, src) - require.NoErrorf(t, err, "unexpected error: %v", err) - plainCode := dst.String() - - require.Equalf(t, plainCode, ex.code, "%d: non-preserving ToComments(); got %q, want %q", i, plainCode, ex.code) - require.Equalf(t, len(fps), ex.wfps, "%d: got %d failpoints but expected %d", i, len(fps), ex.wfps) - } -}