diff --git a/internal/parsers/all.go b/internal/parsers/all.go index 4decc13..615f90c 100644 --- a/internal/parsers/all.go +++ b/internal/parsers/all.go @@ -2,6 +2,7 @@ package parsers import ( _ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/clangtidy" + _ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/cppcheck" _ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/cpplint" _ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/diff" _ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/dummy" diff --git a/internal/parsers/cppcheck/parser.go b/internal/parsers/cppcheck/parser.go index 43fc534..69f39cc 100644 --- a/internal/parsers/cppcheck/parser.go +++ b/internal/parsers/cppcheck/parser.go @@ -1,7 +1,9 @@ package cppcheck import ( + "encoding/json" "fmt" + "strings" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" "github.com/criyle/go-judge/envexec" @@ -9,9 +11,23 @@ import ( type CppCheck struct{} +type Match struct { + Severity []string + Score int +} + type Conf struct { - Score int `default:"100"` - Comment string `default:""` + Score int `default:"100"` + Matches []Match +} + +type Record struct { + File string `json:"file"` + Line int `json:"line"` + Column int `json:"column"` + Severity string `json:"severity"` + Message string `json:"message"` + Id string `json:"id"` } func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult { @@ -27,9 +43,30 @@ func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult { ), } } + records := make([]Record, 0) + lines := strings.Split(stderr, "\n") + for _, line := range lines { + if strings.TrimSpace(line) == "" { + continue + } + var record Record + _ = json.Unmarshal([]byte(line), &record) + records = append(records, record) + } + comment, score, err := GetResult(records, conf) + if err != nil { + return stage.ParserResult{ + Score: 0, + Comment: fmt.Sprintf( + "Unexpected parser error: %s.", + err, + ), + } + } + return stage.ParserResult{ - Score: 0, - Comment: "", + Score: score, + Comment: comment, } } diff --git a/internal/parsers/cppcheck/score.go b/internal/parsers/cppcheck/score.go new file mode 100644 index 0000000..d6028fb --- /dev/null +++ b/internal/parsers/cppcheck/score.go @@ -0,0 +1,66 @@ +package cppcheck + +import "fmt" + +type Severity int + +const ( + ERROR Severity = iota + WARNING + PROBABILITY + PERFORMANCE + STYLE + INFORMATION + UNKNOWN +) + +func severityFromString(severityString string) (Severity, error) { + switch severityString { + case "error": + return ERROR, nil + case "warning": + return WARNING, nil + case "probability": + return PROBABILITY, nil + case "performance": + return PERFORMANCE, nil + case "style": + return STYLE, nil + case "information": + return INFORMATION, nil + default: + return UNKNOWN, fmt.Errorf("unkown severity type \"%s\" for cppcheck", severityString) + } +} + +func GetResult(records []Record, conf Conf) (string, int, error) { + result := "### Test results summary\n\n" + var severityCounts [6]int + var severityScore [6]int + score := conf.Score + + for _, match := range conf.Matches { + severities := match.Severity + score := match.Score + for _, severityString := range severities { + severity, err := severityFromString(severityString) + if err != nil { + return "", 0, err + } + severityScore[int(severity)] = score + } + } + + for _, record := range records { + severity, _ := severityFromString(record.Severity) + severityCounts[int(severity)] += 1 + score -= severityScore[int(severity)] + } + result += fmt.Sprintf("1. error: %d\n", severityCounts[0]) + result += fmt.Sprintf("2. warning: %d\n", severityCounts[1]) + result += fmt.Sprintf("3. probability: %d\n", severityCounts[2]) + result += fmt.Sprintf("4. performance: %d\n", severityCounts[3]) + result += fmt.Sprintf("5. style: %d\n", severityCounts[4]) + result += fmt.Sprintf("6. information: %d", severityCounts[5]) + return result, score, nil +}