feat: option ignoring whitespace

This commit is contained in:
zzjc1234 2024-09-09 12:58:38 +08:00 committed by Boming Zhang
parent 756a531bac
commit 96c71bcd63
GPG Key ID: D47306D7062CDA9D

View File

@ -4,14 +4,16 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"unicode"
"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
) )
type Conf struct { type Conf struct {
Cases []struct { Cases []struct {
Score int Score int
StdoutPath string StdoutPath string
ignoreWhitespace bool
} }
} }
@ -43,8 +45,9 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) (
"executor status: run time: %d ns, memory: %d bytes\n", "executor status: run time: %d ns, memory: %d bytes\n",
result.RunTime, result.Memory, result.RunTime, result.Memory,
) )
// If no difference, assign score // If no difference, assign score
if string(stdout) == result.Files["stdout"] { if compareChars(string(stdout), result.Files["stdout"], caseConf.ignoreWhitespace) {
score = caseConf.Score score = caseConf.Score
} else { } else {
// Convert stdout to string and split by lines // Convert stdout to string and split by lines
@ -52,7 +55,7 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) (
resultLines := strings.Split(result.Files["stdout"], "\n") resultLines := strings.Split(result.Files["stdout"], "\n")
// Find the first difference // Find the first difference
diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines) diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines, caseConf.ignoreWhitespace)
if diffIndex != -1 { if diffIndex != -1 {
// Generate diff block with surrounding context // Generate diff block with surrounding context
diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffIndex, 10) diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffIndex, 10)
@ -73,15 +76,43 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) (
return res, false, nil return res, false, nil
} }
// compareChars compares two strings character by character, optionally ignoring whitespace.
func compareChars(stdout, result string, ignoreWhitespace bool) bool {
if ignoreWhitespace {
stdout = removeWhitespace(stdout)
result = removeWhitespace(result)
}
return stdout == result
}
// removeWhitespace removes all whitespace characters from the string.
func removeWhitespace(s string) string {
var b strings.Builder
for _, r := range s {
if !unicode.IsSpace(r) {
b.WriteRune(r)
}
}
return b.String()
}
// findFirstDifferenceIndex finds the index of the first line where stdout and result differ. // findFirstDifferenceIndex finds the index of the first line where stdout and result differ.
func findFirstDifferenceIndex(stdoutLines, resultLines []string) int { func findFirstDifferenceIndex(stdoutLines, resultLines []string, ignoreWhitespace bool) int {
maxLines := len(stdoutLines) maxLines := len(stdoutLines)
if len(resultLines) > maxLines { if len(resultLines) > maxLines {
maxLines = len(resultLines) maxLines = len(resultLines)
} }
for i := 0; i < maxLines; i++ { for i := 0; i < maxLines; i++ {
if i >= len(stdoutLines) || i >= len(resultLines) || stdoutLines[i] != resultLines[i] { stdoutLine := stdoutLines[i]
resultLine := resultLines[i]
if ignoreWhitespace {
stdoutLine = removeWhitespace(stdoutLine)
resultLine = removeWhitespace(resultLine)
}
if stdoutLine != resultLine {
return i return i
} }
} }
@ -103,74 +134,43 @@ func generateDiffWithContext(stdoutLines, resultLines []string, index, contextSi
// Adding context before the diff // Adding context before the diff
for i := start; i < index; i++ { for i := start; i < index; i++ {
if i < len(stdoutLines) || i < len(resultLines) { stdoutLine, resultLine := getLine(stdoutLines, resultLines, i)
stdoutLine := "" if stdoutLine != resultLine {
if i < len(stdoutLines) { diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine))
stdoutLine = stdoutLines[i] diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine))
} } else {
resultLine := "" diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine))
if i < len(resultLines) {
resultLine = resultLines[i]
}
if stdoutLine != resultLine {
if stdoutLine != "" {
diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine))
}
if resultLine != "" {
diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine))
}
} else {
diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine))
}
} }
} }
// Adding the diff line // Adding the diff line
if index < len(stdoutLines) || index < len(resultLines) { stdoutLine, resultLine := getLine(stdoutLines, resultLines, index)
stdoutLine := "" if stdoutLine != resultLine {
if index < len(stdoutLines) { diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine))
stdoutLine = stdoutLines[index] diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine))
}
resultLine := ""
if index < len(resultLines) {
resultLine = resultLines[index]
}
if stdoutLine != resultLine {
if stdoutLine != "" {
diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine))
}
if resultLine != "" {
diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine))
}
}
} }
// Adding context after the diff // Adding context after the diff
for i := index + 1; i < end; i++ { for i := index + 1; i < end; i++ {
if i < len(stdoutLines) || i < len(resultLines) { stdoutLine, resultLine := getLine(stdoutLines, resultLines, i)
stdoutLine := "" if stdoutLine != resultLine {
if i < len(stdoutLines) { diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine))
stdoutLine = stdoutLines[i] diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine))
} } else {
resultLine := "" diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine))
if i < len(resultLines) {
resultLine = resultLines[i]
}
if stdoutLine != resultLine {
if stdoutLine != "" {
diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine))
}
if resultLine != "" {
diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine))
}
} else {
diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine))
}
} }
} }
return diffBuilder.String() return diffBuilder.String()
} }
// getLine safely retrieves lines from both stdout and result
func getLine(stdoutLines, resultLines []string, i int) (stdoutLine, resultLine string) {
if i < len(stdoutLines) {
stdoutLine = stdoutLines[i]
}
if i < len(resultLines) {
resultLine = resultLines[i]
}
return
}