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 01/10] 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() +} -- 2.30.2 From 756a531bacc28e694a4a0c4b9a9ce47cb9db2e8a Mon Sep 17 00:00:00 2001 From: zzjc1234 <2359047351@qq.com> Date: Sun, 8 Sep 2024 00:37:09 +0800 Subject: [PATCH 02/10] feat: diff blocks --- internal/parsers/diff/parser.go | 105 ++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 19 deletions(-) diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go index f069d74..c4e617b 100644 --- a/internal/parsers/diff/parser.go +++ b/internal/parsers/diff/parser.go @@ -39,13 +39,13 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( return nil, true, err } + comment = fmt.Sprintf( + "executor status: run time: %d ns, memory: %d bytes\n", + result.RunTime, result.Memory, + ) // If no difference, assign score if string(stdout) == result.Files["stdout"] { score = caseConf.Score - 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") @@ -54,14 +54,12 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( // 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", + // Generate diff block with surrounding context + diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffIndex, 10) + comment += fmt.Sprintf( + "difference found at line %d:\n```diff\n%s```", diffIndex+1, - resultContext, - stdoutContext, + diffOutput, ) } } @@ -90,20 +88,89 @@ func findFirstDifferenceIndex(stdoutLines, resultLines []string) int { return -1 } -// getContextLines returns the surrounding lines of the specified index. -func getContextLines(lines []string, index, contextSize int) string { +// generateDiffWithContext creates a diff block with surrounding context from stdout and result. +func generateDiffWithContext(stdoutLines, resultLines []string, index, contextSize int) string { + var diffBuilder strings.Builder + start := index - contextSize if start < 0 { start = 0 } end := index + contextSize + 1 - if end > len(lines) { - end = len(lines) + if end > len(stdoutLines) { + end = len(stdoutLines) } - var context strings.Builder - for i := start; i < end; i++ { - context.WriteString(fmt.Sprintf("%d: %s\n", i+1, lines[i])) + // Adding context before the diff + for i := start; i < index; i++ { + if i < len(stdoutLines) || i < len(resultLines) { + stdoutLine := "" + if i < len(stdoutLines) { + stdoutLine = stdoutLines[i] + } + resultLine := "" + 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 context.String() + + // Adding the diff line + if index < len(stdoutLines) || index < len(resultLines) { + stdoutLine := "" + if index < len(stdoutLines) { + stdoutLine = stdoutLines[index] + } + 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 + for i := index + 1; i < end; i++ { + if i < len(stdoutLines) || i < len(resultLines) { + stdoutLine := "" + if i < len(stdoutLines) { + stdoutLine = stdoutLines[i] + } + resultLine := "" + 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() } -- 2.30.2 From 96c71bcd636023ee74144ea2678b1f4531036137 Mon Sep 17 00:00:00 2001 From: zzjc1234 <2359047351@qq.com> Date: Mon, 9 Sep 2024 12:58:38 +0800 Subject: [PATCH 03/10] feat: option ignoring whitespace --- internal/parsers/diff/parser.go | 128 ++++++++++++++++---------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go index c4e617b..0c32393 100644 --- a/internal/parsers/diff/parser.go +++ b/internal/parsers/diff/parser.go @@ -4,14 +4,16 @@ import ( "fmt" "os" "strings" + "unicode" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" ) type Conf struct { Cases []struct { - Score int - StdoutPath string + Score int + 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", result.RunTime, result.Memory, ) + // If no difference, assign score - if string(stdout) == result.Files["stdout"] { + if compareChars(string(stdout), result.Files["stdout"], caseConf.ignoreWhitespace) { score = caseConf.Score } else { // 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") // Find the first difference - diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines) + diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines, caseConf.ignoreWhitespace) if diffIndex != -1 { // Generate diff block with surrounding context diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffIndex, 10) @@ -73,15 +76,43 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( 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. -func findFirstDifferenceIndex(stdoutLines, resultLines []string) int { +func findFirstDifferenceIndex(stdoutLines, resultLines []string, ignoreWhitespace bool) 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] { + stdoutLine := stdoutLines[i] + resultLine := resultLines[i] + + if ignoreWhitespace { + stdoutLine = removeWhitespace(stdoutLine) + resultLine = removeWhitespace(resultLine) + } + + if stdoutLine != resultLine { return i } } @@ -103,74 +134,43 @@ func generateDiffWithContext(stdoutLines, resultLines []string, index, contextSi // Adding context before the diff for i := start; i < index; i++ { - if i < len(stdoutLines) || i < len(resultLines) { - stdoutLine := "" - if i < len(stdoutLines) { - stdoutLine = stdoutLines[i] - } - resultLine := "" - 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)) - } + stdoutLine, resultLine := getLine(stdoutLines, resultLines, i) + if stdoutLine != resultLine { + diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine)) + diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine)) + } else { + diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine)) } } // Adding the diff line - if index < len(stdoutLines) || index < len(resultLines) { - stdoutLine := "" - if index < len(stdoutLines) { - stdoutLine = stdoutLines[index] - } - 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)) - } - } + stdoutLine, resultLine := getLine(stdoutLines, resultLines, index) + if stdoutLine != resultLine { + diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine)) + diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine)) } // Adding context after the diff for i := index + 1; i < end; i++ { - if i < len(stdoutLines) || i < len(resultLines) { - stdoutLine := "" - if i < len(stdoutLines) { - stdoutLine = stdoutLines[i] - } - resultLine := "" - 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)) - } + stdoutLine, resultLine := getLine(stdoutLines, resultLines, i) + if stdoutLine != resultLine { + diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine)) + diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine)) + } else { + diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine)) } } 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 +} -- 2.30.2 From 6fbbe7ece0a0659c3c859ddbe5b24abfb71a892a Mon Sep 17 00:00:00 2001 From: zzjc1234 <2359047351@qq.com> Date: Mon, 9 Sep 2024 13:08:29 +0800 Subject: [PATCH 04/10] feat: option ignoring whitespace --- internal/parsers/diff/parser.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go index 0c32393..d56d037 100644 --- a/internal/parsers/diff/parser.go +++ b/internal/parsers/diff/parser.go @@ -13,7 +13,7 @@ type Conf struct { Cases []struct { Score int StdoutPath string - ignoreWhitespace bool + IgnoreWhitespace bool } } @@ -47,7 +47,7 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( ) // If no difference, assign score - if compareChars(string(stdout), result.Files["stdout"], caseConf.ignoreWhitespace) { + if compareChars(string(stdout), result.Files["stdout"], caseConf.IgnoreWhitespace) { score = caseConf.Score } else { // Convert stdout to string and split by lines @@ -55,7 +55,7 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( resultLines := strings.Split(result.Files["stdout"], "\n") // Find the first difference - diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines, caseConf.ignoreWhitespace) + diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines, caseConf.IgnoreWhitespace) if diffIndex != -1 { // Generate diff block with surrounding context diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffIndex, 10) -- 2.30.2 From 1d90d7297890af408dcef1c10b4237b155801e93 Mon Sep 17 00:00:00 2001 From: zzjc1234 <2359047351@qq.com> Date: Tue, 10 Sep 2024 16:21:20 +0800 Subject: [PATCH 05/10] feat: myers --- internal/parsers/diff/parser.go | 199 +++++++++++++++++++++----------- 1 file changed, 129 insertions(+), 70 deletions(-) diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go index d56d037..c4f7fe8 100644 --- a/internal/parsers/diff/parser.go +++ b/internal/parsers/diff/parser.go @@ -9,6 +9,15 @@ import ( "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" ) +// operation represents the type of edit operation. +type operation uint + +const ( + INSERT operation = iota + 1 + DELETE + MOVE +) + type Conf struct { Cases []struct { Score int @@ -54,17 +63,15 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( stdoutLines := strings.Split(string(stdout), "\n") resultLines := strings.Split(result.Files["stdout"], "\n") - // Find the first difference - diffIndex := findFirstDifferenceIndex(stdoutLines, resultLines, caseConf.IgnoreWhitespace) - if diffIndex != -1 { - // Generate diff block with surrounding context - diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffIndex, 10) - comment += fmt.Sprintf( - "difference found at line %d:\n```diff\n%s```", - diffIndex+1, - diffOutput, - ) - } + // Generate Myers diff + diffOps := myersDiff(stdoutLines, resultLines) + + // Generate diff block with surrounding context + diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffOps) + comment += fmt.Sprintf( + "difference found:\n```diff\n%s```", + diffOutput, + ) } res = append(res, stage.ParserResult{ @@ -96,81 +103,133 @@ func removeWhitespace(s string) string { return b.String() } -// findFirstDifferenceIndex finds the index of the first line where stdout and result differ. -func findFirstDifferenceIndex(stdoutLines, resultLines []string, ignoreWhitespace bool) int { - maxLines := len(stdoutLines) - if len(resultLines) > maxLines { - maxLines = len(resultLines) - } +// myersDiff computes the Myers' diff between two slices of strings. +func myersDiff(src, dst []string) []operation { + n := len(src) + m := len(dst) + max := n + m + var trace []map[int]int + var x, y int - for i := 0; i < maxLines; i++ { - stdoutLine := stdoutLines[i] - resultLine := resultLines[i] +loop: + for d := 0; d <= max; d++ { + v := make(map[int]int, d+2) + trace = append(trace, v) - if ignoreWhitespace { - stdoutLine = removeWhitespace(stdoutLine) - resultLine = removeWhitespace(resultLine) + if d == 0 { + t := 0 + for len(src) > t && len(dst) > t && src[t] == dst[t] { + t++ + } + v[0] = t + if t == len(src) && t == len(dst) { + break loop + } + continue } - if stdoutLine != resultLine { - return i + lastV := trace[d-1] + + for k := -d; k <= d; k += 2 { + if k == -d || (k != d && lastV[k-1] < lastV[k+1]) { + x = lastV[k+1] + } else { + x = lastV[k-1] + 1 + } + + y = x - k + + for x < n && y < m && src[x] == dst[y] { + x, y = x+1, y+1 + } + + v[k] = x + + if x == n && y == m { + break loop + } } } - return -1 + + var script []operation + x = n + y = m + var k, prevK, prevX, prevY int + + for d := len(trace) - 1; d > 0; d-- { + k = x - y + lastV := trace[d-1] + + if k == -d || (k != d && lastV[k-1] < lastV[k+1]) { + prevK = k + 1 + } else { + prevK = k - 1 + } + + prevX = lastV[prevK] + prevY = prevX - prevK + + for x > prevX && y > prevY { + script = append(script, MOVE) + x -= 1 + y -= 1 + } + + if x == prevX { + script = append(script, INSERT) + } else { + script = append(script, DELETE) + } + + x, y = prevX, prevY + } + + if trace[0][0] != 0 { + for i := 0; i < trace[0][0]; i++ { + script = append(script, MOVE) + } + } + + return reverse(script) +} + +// reverse reverses a slice of operations. +func reverse(s []operation) []operation { + result := make([]operation, len(s)) + for i, v := range s { + result[len(s)-1-i] = v + } + return result } // generateDiffWithContext creates a diff block with surrounding context from stdout and result. -func generateDiffWithContext(stdoutLines, resultLines []string, index, contextSize int) string { +func generateDiffWithContext(stdoutLines, resultLines []string, ops []operation) string { var diffBuilder strings.Builder - start := index - contextSize - if start < 0 { - start = 0 - } - end := index + contextSize + 1 - if end > len(stdoutLines) { - end = len(stdoutLines) - } + srcIndex, dstIndex := 0, 0 - // Adding context before the diff - for i := start; i < index; i++ { - stdoutLine, resultLine := getLine(stdoutLines, resultLines, i) - if stdoutLine != resultLine { - diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine)) - diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine)) - } else { - diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine)) - } - } + for _, op := range ops { + switch op { + case INSERT: + if dstIndex < len(resultLines) { + diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLines[dstIndex])) + dstIndex++ + } - // Adding the diff line - stdoutLine, resultLine := getLine(stdoutLines, resultLines, index) - if stdoutLine != resultLine { - diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine)) - diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine)) - } + case MOVE: + if srcIndex < len(stdoutLines) { + diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLines[srcIndex])) + srcIndex++ + dstIndex++ + } - // Adding context after the diff - for i := index + 1; i < end; i++ { - stdoutLine, resultLine := getLine(stdoutLines, resultLines, i) - if stdoutLine != resultLine { - diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLine)) - diffBuilder.WriteString(fmt.Sprintf("+ %s\n", resultLine)) - } else { - diffBuilder.WriteString(fmt.Sprintf(" %s\n", stdoutLine)) + case DELETE: + if srcIndex < len(stdoutLines) { + diffBuilder.WriteString(fmt.Sprintf("- %s\n", stdoutLines[srcIndex])) + srcIndex++ + } } } 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 -} -- 2.30.2 From fdf84546da1847e7679ba2750e56c912c10fcf6a Mon Sep 17 00:00:00 2001 From: zzjc1234 <2359047351@qq.com> Date: Tue, 10 Sep 2024 18:58:28 +0800 Subject: [PATCH 06/10] chore: gitmodules --- .gitmodules | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitmodules b/.gitmodules index 4c093ae..9261291 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,11 @@ +[submodule "examples/diff/basic"] + path = examples/diff/basic + url = ssh://git@focs.ji.sjtu.edu.cn:2222/FOCS-dev/JOJ3-examples.git + branch = diff/basic +[submodule "examples/diff/complex"] + path = examples/diff/complex + url = ssh://git@focs.ji.sjtu.edu.cn:2222/FOCS-dev/JOJ3-examples.git + branch = diff/complex [submodule "examples/cpplint/sillycode"] path = examples/cpplint/sillycode url = ssh://git@focs.ji.sjtu.edu.cn:2222/FOCS-dev/JOJ3-examples.git -- 2.30.2 From 776de48d03c116d9c6b796bca3bf80d7e6a771e7 Mon Sep 17 00:00:00 2001 From: Boming Zhang Date: Tue, 10 Sep 2024 21:41:33 -0400 Subject: [PATCH 07/10] chore: git submodule files --- examples/diff/basic | 1 + examples/diff/complex | 1 + 2 files changed, 2 insertions(+) create mode 160000 examples/diff/basic create mode 160000 examples/diff/complex diff --git a/examples/diff/basic b/examples/diff/basic new file mode 160000 index 0000000..11a3335 --- /dev/null +++ b/examples/diff/basic @@ -0,0 +1 @@ +Subproject commit 11a33358f6b78efa665cfa8a183441400281abb4 diff --git a/examples/diff/complex b/examples/diff/complex new file mode 160000 index 0000000..a397a21 --- /dev/null +++ b/examples/diff/complex @@ -0,0 +1 @@ +Subproject commit a397a2196442e34888ac890dab799c3856bba745 -- 2.30.2 From 2c742852fba34e3ae2652bb510a23672a2414022 Mon Sep 17 00:00:00 2001 From: zzjc1234 <2359047351@qq.com> Date: Wed, 11 Sep 2024 12:02:22 +0800 Subject: [PATCH 08/10] chore: update submodules --- examples/diff/basic | 2 +- examples/diff/complex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/diff/basic b/examples/diff/basic index 11a3335..d8d66fb 160000 --- a/examples/diff/basic +++ b/examples/diff/basic @@ -1 +1 @@ -Subproject commit 11a33358f6b78efa665cfa8a183441400281abb4 +Subproject commit d8d66fb5b47b5e79e08532da31d397a5d461f087 diff --git a/examples/diff/complex b/examples/diff/complex index a397a21..fc77411 160000 --- a/examples/diff/complex +++ b/examples/diff/complex @@ -1 +1 @@ -Subproject commit a397a2196442e34888ac890dab799c3856bba745 +Subproject commit fc774118794a5c5ec0b88863ba6c8492e5b13f89 -- 2.30.2 From eac7a62ebe16d5ff94aa8844eebf65cc5a621190 Mon Sep 17 00:00:00 2001 From: Boming Zhang Date: Wed, 11 Sep 2024 06:07:07 -0400 Subject: [PATCH 09/10] chore: add source --- internal/parsers/diff/parser.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go index c4f7fe8..86fe863 100644 --- a/internal/parsers/diff/parser.go +++ b/internal/parsers/diff/parser.go @@ -104,6 +104,7 @@ func removeWhitespace(s string) string { } // myersDiff computes the Myers' diff between two slices of strings. +// src: https://github.com/cj1128/myers-diff/blob/master/main.go func myersDiff(src, dst []string) []operation { n := len(src) m := len(dst) @@ -122,7 +123,7 @@ loop: t++ } v[0] = t - if t == len(src) && t == len(dst) { + if t == len(src) && len(src) == len(dst) { break loop } continue -- 2.30.2 From 52491478a442724c2083809c1a959a3d7f2d4f5c Mon Sep 17 00:00:00 2001 From: Boming Zhang Date: Wed, 11 Sep 2024 07:06:11 -0400 Subject: [PATCH 10/10] feat: diff parser with multiple outputs in one case --- examples/compile/error | 2 +- examples/compile/success | 2 +- examples/diff/basic | 2 +- examples/diff/complex | 2 +- internal/parsers/diff/parser.go | 57 ++++++++++++++++----------------- 5 files changed, 32 insertions(+), 33 deletions(-) diff --git a/examples/compile/error b/examples/compile/error index 2593e79..4e5fab9 160000 --- a/examples/compile/error +++ b/examples/compile/error @@ -1 +1 @@ -Subproject commit 2593e79505a93042d308c5fc355dba671dd4fdba +Subproject commit 4e5fab93e5a0ce67c8f40fef1e8f4cab7018fc5d diff --git a/examples/compile/success b/examples/compile/success index 638e9f6..1512cb5 160000 --- a/examples/compile/success +++ b/examples/compile/success @@ -1 +1 @@ -Subproject commit 638e9f661092d39daaf6e1ffc8ba5998fc56c96a +Subproject commit 1512cb5f20473a598d7504a08dacff3d6406b983 diff --git a/examples/diff/basic b/examples/diff/basic index d8d66fb..af99032 160000 --- a/examples/diff/basic +++ b/examples/diff/basic @@ -1 +1 @@ -Subproject commit d8d66fb5b47b5e79e08532da31d397a5d461f087 +Subproject commit af990327ab095c22a383448ad70d915f8d10490b diff --git a/examples/diff/complex b/examples/diff/complex index fc77411..ac7a2fc 160000 --- a/examples/diff/complex +++ b/examples/diff/complex @@ -1 +1 @@ -Subproject commit fc774118794a5c5ec0b88863ba6c8492e5b13f89 +Subproject commit ac7a2fc912fb51af156cd4babb7e72148ebe1c14 diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go index 86fe863..ebcccb7 100644 --- a/internal/parsers/diff/parser.go +++ b/internal/parsers/diff/parser.go @@ -20,9 +20,12 @@ const ( type Conf struct { Cases []struct { - Score int - StdoutPath string - IgnoreWhitespace bool + Outputs []struct { + Score int + FileName string + AnswerPath string + IgnoreWhitespace bool + } } } @@ -43,35 +46,31 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) ( for i, caseConf := range conf.Cases { result := results[i] score := 0 - var comment string + comment := "" + for _, output := range caseConf.Outputs { + answer, err := os.ReadFile(output.AnswerPath) + if err != nil { + return nil, true, err + } - stdout, err := os.ReadFile(caseConf.StdoutPath) - if err != nil { - return nil, true, err - } + // If no difference, assign score + if compareChars(string(answer), result.Files[output.FileName], output.IgnoreWhitespace) { + score += output.Score + } else { + // Convert answer to string and split by lines + stdoutLines := strings.Split(string(answer), "\n") + resultLines := strings.Split(result.Files[output.FileName], "\n") - comment = fmt.Sprintf( - "executor status: run time: %d ns, memory: %d bytes\n", - result.RunTime, result.Memory, - ) + // Generate Myers diff + diffOps := myersDiff(stdoutLines, resultLines) - // If no difference, assign score - if compareChars(string(stdout), result.Files["stdout"], caseConf.IgnoreWhitespace) { - score = caseConf.Score - } else { - // Convert stdout to string and split by lines - stdoutLines := strings.Split(string(stdout), "\n") - resultLines := strings.Split(result.Files["stdout"], "\n") - - // Generate Myers diff - diffOps := myersDiff(stdoutLines, resultLines) - - // Generate diff block with surrounding context - diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffOps) - comment += fmt.Sprintf( - "difference found:\n```diff\n%s```", - diffOutput, - ) + // Generate diff block with surrounding context + diffOutput := generateDiffWithContext(stdoutLines, resultLines, diffOps) + comment += fmt.Sprintf( + "difference found in %s:\n```diff\n%s```\n", + output.FileName, diffOutput, + ) + } } res = append(res, stage.ParserResult{ -- 2.30.2