feat: diff parser #33
| 
						 | 
					@ -3,6 +3,7 @@ package diff
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
 | 
						"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) {
 | 
						if len(conf.Cases) != len(results) {
 | 
				
			||||||
		return nil, true, fmt.Errorf("cases number not match")
 | 
							return nil, true, fmt.Errorf("cases number not match")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var res []stage.ParserResult
 | 
						var res []stage.ParserResult
 | 
				
			||||||
	for i, caseConf := range conf.Cases {
 | 
						for i, caseConf := range conf.Cases {
 | 
				
			||||||
		result := results[i]
 | 
							result := results[i]
 | 
				
			||||||
		score := 0
 | 
							score := 0
 | 
				
			||||||
 | 
							var comment string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		stdout, err := os.ReadFile(caseConf.StdoutPath)
 | 
							stdout, err := os.ReadFile(caseConf.StdoutPath)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, true, err
 | 
								return nil, true, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// TODO: more compare strategies
 | 
					
 | 
				
			||||||
 | 
							// If no difference, assign score
 | 
				
			||||||
		if string(stdout) == result.Files["stdout"] {
 | 
							if string(stdout) == result.Files["stdout"] {
 | 
				
			||||||
			score = caseConf.Score
 | 
								score = caseConf.Score
 | 
				
			||||||
		}
 | 
								comment = fmt.Sprintf(
 | 
				
			||||||
		res = append(res, stage.ParserResult{
 | 
					 | 
				
			||||||
			Score: score,
 | 
					 | 
				
			||||||
			Comment: fmt.Sprintf(
 | 
					 | 
				
			||||||
				"executor status: run time: %d ns, memory: %d bytes",
 | 
									"executor status: run time: %d ns, memory: %d bytes",
 | 
				
			||||||
				result.RunTime, result.Memory,
 | 
									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
 | 
						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()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user