Skip to content

Commit

Permalink
extend parsing instructions to use json object instead of plain txt (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mfederowicz authored Nov 26, 2023
1 parent 9a2eab3 commit 9e80d93
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 5 deletions.
17 changes: 17 additions & 0 deletions test/json-data-format_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package test

import (
"testing"

"github.com/mgechev/revive/lint"
"github.com/mgechev/revive/rule"
)

func TestJsonDataFormat(t *testing.T) {
testRule(t, "json-data-format-atomic", &rule.AtomicRule{})

}
func TestJsonDataFormatVarNaming(t *testing.T) {
testRule(t, "json-data-format-var-naming", &rule.VarNamingRule{}, &lint.RuleConfig{})

}
70 changes: 65 additions & 5 deletions test/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package test
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"go/ast"
"go/parser"
Expand Down Expand Up @@ -89,6 +90,7 @@ func assertFailures(t *testing.T, baseDir string, fi os.FileInfo, src []byte, ru
if p.Position.Start.Line != in.Line {
continue
}

if in.Match == p.Failure {
// check replacement if we are expecting one
if in.Replacement != "" {
Expand All @@ -102,6 +104,14 @@ func assertFailures(t *testing.T, baseDir string, fi os.FileInfo, src []byte, ru
}
}

if in.Confidence > 0 {

if in.Confidence != p.Confidence {
t.Errorf("Lint failed at %s:%d; got confidence %f, want %f", fi.Name(), in.Line, p.Confidence, in.Confidence)
}

}

// remove this problem from ps
copy(failures[i:], failures[i+1:])
failures = failures[:len(failures)-1]
Expand All @@ -122,9 +132,19 @@ func assertFailures(t *testing.T, baseDir string, fi os.FileInfo, src []byte, ru
}

type instruction struct {
Line int // the line number this applies to
Match string // which pattern to match
Replacement string // what the suggested replacement line should be
Line int // the line number this applies to
Match string // which pattern to match
Replacement string // what the suggested replacement line should be
RuleName string // what rule we use
Category string // which category
Confidence float64 // confidence level
}

// JSONInstruction structure used when we parse json object insted of classic MATCH string
type JSONInstruction struct {
Match string `json:"MATCH"`
Category string `json:"Category"`
Confidence float64 `json:"Confidence"`
}

// parseInstructions parses instructions from the comments in a Go source file.
Expand All @@ -140,15 +160,23 @@ func parseInstructions(t *testing.T, filename string, src []byte) []instruction
ln := fset.Position(cg.Pos()).Line
raw := cg.Text()
for _, line := range strings.Split(raw, "\n") {
if line == "" || strings.HasPrefix(line, "#") {
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "ignore") {
continue
}
if line == "OK" && ins == nil {
// so our return value will be non-nil
ins = make([]instruction, 0)
continue
}
if strings.Contains(line, "MATCH") {
switch extractDataMode(line) {
case "json":
jsonInst, err := extractInstructionFromJSON(strings.TrimPrefix(line, "json:"), ln)
if err != nil {
t.Fatalf("At %v:%d: %v", filename, ln, err)
}
ins = append(ins, jsonInst)
break
case "classic":
match, err := extractPattern(line)
if err != nil {
t.Fatalf("At %v:%d: %v", filename, ln, err)
Expand All @@ -172,12 +200,44 @@ func parseInstructions(t *testing.T, filename string, src []byte) []instruction
Match: match,
Replacement: repl,
})
break
}

}
}
return ins
}

func extractInstructionFromJSON(line string, lineNumber int) (instruction, error) {
// Use the json.Unmarshal function to parse the JSON into the struct
var jsonInst JSONInstruction
if err := json.Unmarshal([]byte(line), &jsonInst); err != nil {
fmt.Println("Error parsing JSON:", err)
}

ins := instruction{
Match: jsonInst.Match,
Confidence: jsonInst.Confidence,
Category: jsonInst.Category,
Line: lineNumber,
}
return ins, nil

}

func extractDataMode(line string) string {

if strings.HasPrefix(line, "json") {
return "json"
}
if strings.Contains(line, "MATCH") {
return "classic"
}

return ""

}

func extractPattern(line string) (string, error) {
a, b := strings.Index(line, "/"), strings.LastIndex(line, "/")
if a == -1 || a == b {
Expand Down
13 changes: 13 additions & 0 deletions testdata/json-data-format-atomic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fixtures

import (
"sync/atomic"
)

type Counter uint64

func AtomicTests() {
x = atomic.AddUint64(&x, 1) // json:{"MATCH": "direct assignment to atomic value","Confidence": 1}
x := uint64(1)

}
8 changes: 8 additions & 0 deletions testdata/json-data-format-var-naming.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package fixtures

func foo() string {
customID := "result" // ignore
customVm := "result" // json:{"MATCH": "var customVm should be customVM"}
CUSTOMER_UP := "result" // json:{"MATCH": "don't use ALL_CAPS in Go names; use CamelCase", "Confidence": 0.8}
return customId
}

0 comments on commit 9e80d93

Please sign in to comment.