From fd69aebac5a3bf0707d9f3d01106d7eb5a5d5773 Mon Sep 17 00:00:00 2001 From: zzjc1234 <2359047351@qq.com> Date: Sat, 7 Sep 2024 23:59:28 +0800 Subject: [PATCH] feat: diff --- internal/parsers/diff/parser.go | 71 ++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go index 7c70d9f..f069d74 100644 --- a/internal/parsers/diff/parser.go +++ b/internal/parsers/diff/parser.go @@ -3,6 +3,7 @@ package diff import ( "fmt" "os" + "strings" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" ) @@ -26,25 +27,83 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( if len(conf.Cases) != len(results) { return nil, true, fmt.Errorf("cases number not match") } + var res []stage.ParserResult for i, caseConf := range conf.Cases { result := results[i] score := 0 + var comment string + stdout, err := os.ReadFile(caseConf.StdoutPath) if err != nil { return nil, true, err } - // TODO: more compare strategies + + // If no difference, assign score if string(stdout) == result.Files["stdout"] { score = caseConf.Score - } - res = append(res, stage.ParserResult{ - Score: score, - Comment: fmt.Sprintf( + comment = fmt.Sprintf( "executor status: run time: %d ns, memory: %d bytes", result.RunTime, result.Memory, - ), + ) + } else { + // Convert stdout to string and split by lines + stdoutLines := strings.Split(string(stdout), "\n") + resultLines := strings.Split(result.Files["stdout"], "\n") + + // Find the first difference + diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines) + if diffIndex != -1 { + // Get the surrounding lines from both stdout and result + stdoutContext := getContextLines(stdoutLines, diffIndex, 10) + resultContext := getContextLines(resultLines, diffIndex, 10) + comment = comment + fmt.Sprintf( + "difference found at line %d:\nExpected output:\n%s\nActual output:\n%s", + diffIndex+1, + resultContext, + stdoutContext, + ) + } + } + + res = append(res, stage.ParserResult{ + Score: score, + Comment: comment, }) } + return res, false, nil } + +// findFirstDifferenceIndex finds the index of the first line where stdout and result differ. +func findFirstDifferenceIndex(stdoutLines, resultLines []string) int { + maxLines := len(stdoutLines) + if len(resultLines) > maxLines { + maxLines = len(resultLines) + } + + for i := 0; i < maxLines; i++ { + if i >= len(stdoutLines) || i >= len(resultLines) || stdoutLines[i] != resultLines[i] { + return i + } + } + return -1 +} + +// getContextLines returns the surrounding lines of the specified index. +func getContextLines(lines []string, index, contextSize int) string { + start := index - contextSize + if start < 0 { + start = 0 + } + end := index + contextSize + 1 + if end > len(lines) { + end = len(lines) + } + + var context strings.Builder + for i := start; i < end; i++ { + context.WriteString(fmt.Sprintf("%d: %s\n", i+1, lines[i])) + } + return context.String() +}