go-judge/pkg/diff/diff.go
2019-11-26 01:37:24 -08:00

71 lines
1.5 KiB
Go

package diff
import (
"bufio"
"bytes"
"fmt"
"io"
"unicode"
)
// Compare compares actual with expected.
// if they are the same except space at line / file ending,
// no error is returned
// otherwise, if error occurred / not same, error will be
// returned
func Compare(expected, actual io.Reader) error {
expScan := bufio.NewScanner(expected)
actScan := bufio.NewScanner(actual)
for line := 1; ; line++ {
exp, hasExp := scanTrimRight(expScan)
act, hasAct := scanTrimRight(actScan)
// EOF at the same time
if !hasExp && !hasAct {
return nil
}
// they are not equal
if exp != act {
return newErr(line, exp, act)
}
// they are all exists and equal
if hasExp && hasAct {
continue
}
// verify all empty line lefts
if err := verifyEOFSpace("actual", actScan); err != nil {
return err
}
if err := verifyEOFSpace("expected", expScan); err != nil {
return err
}
// at this point, they should all be same
return nil
}
}
func newErr(line int, exp, act string) error {
return fmt.Errorf("At line %d,\nexpected: %v\nactual: %v", line, exp, act)
}
func scanTrimRight(sc *bufio.Scanner) (string, bool) {
if sc.Scan() {
return trimRight(sc), true
}
return "", false
}
func verifyEOFSpace(name string, sc *bufio.Scanner) error {
for sc.Scan() {
if v := trimRight(sc); v != "" {
return fmt.Errorf("%v have more content: %v", name, v)
}
}
return nil
}
func trimRight(sc *bufio.Scanner) string {
return string(bytes.TrimRightFunc(sc.Bytes(), unicode.IsSpace))
}