go-shout/update.go

123 lines
3.2 KiB
Go

package main
import (
"fmt"
"regexp"
"strings"
)
var exitCodeMarkerRe = regexp.MustCompile(`^\[(\d+|\*)\]$`)
func rewriteFile(file ShoutFile, results []CommandResult, originalContent string) string {
lines := strings.Split(originalContent, "\n")
var output []string
cmdIdx := 0
for i := 0; i < len(lines); i++ {
line := lines[i]
if strings.HasPrefix(line, "$ ") {
output = append(output, line)
if cmdIdx >= len(file.Commands) || cmdIdx >= len(results) {
// Out of bounds — skip past expected output, preserving original lines
j := i + 1
for j < len(lines) && !strings.HasPrefix(lines[j], "$ ") {
j++
}
output = append(output, lines[i+1:j]...)
i = j - 1
cmdIdx++
continue
}
cmd := file.Commands[cmdIdx]
result := results[cmdIdx]
// Skip past old expected output lines
j := i + 1
for j < len(lines) && !strings.HasPrefix(lines[j], "$ ") {
j++
}
oldExpectedRaw := lines[i+1 : j]
// Count trailing blank lines
trailingBlanks := 0
for k := len(oldExpectedRaw) - 1; k >= 0; k-- {
if oldExpectedRaw[k] == "" {
trailingBlanks++
} else {
break
}
}
outputMatch := matchOutput(cmd.Expected, result.Actual)
ecMatch := exitCodeOK(cmd.ExitCodeType, cmd.ExitCodeValue, result.ExitCode)
if outputMatch && ecMatch {
// Both match — preserve original verbatim
output = append(output, oldExpectedRaw...)
} else if outputMatch {
// Output matches but exit code changed — preserve output, fix exit code
raw := oldExpectedRaw
rawTrailing := 0
for k := len(raw) - 1; k >= 0; k-- {
if raw[k] == "" {
rawTrailing++
} else {
break
}
}
content := raw[:len(raw)-rawTrailing]
// Strip old exit code marker if present
if len(content) > 0 && exitCodeMarkerRe.MatchString(content[len(content)-1]) {
content = content[:len(content)-1]
}
output = append(output, content...)
marker := updateExitCodeMarker(cmd, result.ExitCode)
if marker != "" {
output = append(output, marker)
} else if len(content) > 0 && exitCodeMarkerRe.MatchString(content[len(content)-1]) {
output = append(output, "[0]")
}
for k := 0; k < rawTrailing; k++ {
output = append(output, "")
}
} else {
// Output doesn't match — rewrite everything
output = append(output, result.Actual...)
marker := updateExitCodeMarker(cmd, result.ExitCode)
if marker != "" {
output = append(output, marker)
} else if len(result.Actual) > 0 && exitCodeMarkerRe.MatchString(result.Actual[len(result.Actual)-1]) {
output = append(output, "[0]")
}
for k := 0; k < trailingBlanks; k++ {
output = append(output, "")
}
}
i = j - 1
cmdIdx++
} else if cmdIdx == 0 || cmdIdx >= len(file.Commands) {
output = append(output, line)
}
}
return strings.Join(output, "\n")
}
// updateExitCodeMarker returns the exit code marker to write, preserving [*]
// wildcards when the command still exits non-zero.
func updateExitCodeMarker(cmd Command, actualExitCode int) string {
if cmd.ExitCodeType == ExitCodeWildcard && actualExitCode != 0 {
return "[*]"
}
if actualExitCode != 0 {
return fmt.Sprintf("[%d]", actualExitCode)
}
return ""
}