mirror of
https://gitlab.com/TECHNOFAB/nixtest.git
synced 2025-12-12 18:20:11 +01:00
228 lines
6.6 KiB
Go
228 lines
6.6 KiB
Go
package console
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/jedib0t/go-pretty/v6/text"
|
|
"gitlab.com/technofab/nixtest/internal/types"
|
|
)
|
|
|
|
// captureOutput captures stdout and stderr during the execution of a function
|
|
func captureOutput(f func()) (string, string) {
|
|
// save original stdout and stderr
|
|
originalStdout := os.Stdout
|
|
originalStderr := os.Stderr
|
|
|
|
rOut, wOut, _ := os.Pipe()
|
|
rErr, wErr, _ := os.Pipe()
|
|
|
|
os.Stdout = wOut
|
|
os.Stderr = wErr
|
|
|
|
defer func() {
|
|
// restore stdout & stderr
|
|
os.Stdout = originalStdout
|
|
os.Stderr = originalStderr
|
|
}()
|
|
|
|
outC := make(chan string)
|
|
errC := make(chan string)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
var buf bytes.Buffer
|
|
wg.Done()
|
|
_, _ = io.Copy(&buf, rOut)
|
|
outC <- buf.String()
|
|
}()
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
var buf bytes.Buffer
|
|
wg.Done()
|
|
_, _ = io.Copy(&buf, rErr)
|
|
errC <- buf.String()
|
|
}()
|
|
|
|
f()
|
|
|
|
wOut.Close()
|
|
wErr.Close()
|
|
wg.Wait()
|
|
|
|
stdout := <-outC
|
|
stderr := <-errC
|
|
|
|
return stdout, stderr
|
|
}
|
|
|
|
func TestPrintErrorsColor(t *testing.T) {
|
|
results := types.Results{
|
|
"Suite1": []types.TestResult{
|
|
{
|
|
Spec: types.TestSpec{Suite: "Suite1", Name: "TestFailure_Diff"},
|
|
Status: types.StatusFailure,
|
|
Expected: "line1\nline2 expected\nline3",
|
|
Actual: "line1\nline2 actual\nline3",
|
|
},
|
|
},
|
|
}
|
|
stdout, _ := captureOutput(func() {
|
|
PrintErrors(results, false)
|
|
})
|
|
|
|
ansiEscapePattern := `(?:\\x1b\[[0-9;]*m)*`
|
|
pattern := `.*\n` +
|
|
`A|A Diff:\n` +
|
|
`A|A line1\n` +
|
|
`A|A line2 AexpeAAacAAtedAAualA\n` +
|
|
`A|A line3.*`
|
|
pattern = strings.ReplaceAll(pattern, "A", ansiEscapePattern)
|
|
|
|
matched, _ := regexp.MatchString(pattern, stdout)
|
|
|
|
if !matched {
|
|
t.Errorf("PrintErrors() TestFailure_Diff diff output mismatch or missing.\nExpected pattern:\n%s\nGot:\n%s", pattern, stdout)
|
|
}
|
|
}
|
|
|
|
func TestPrintErrors(t *testing.T) {
|
|
text.DisableColors()
|
|
defer text.EnableColors()
|
|
|
|
results := types.Results{
|
|
"Suite1": []types.TestResult{
|
|
{
|
|
Spec: types.TestSpec{Suite: "Suite1", Name: "TestSuccess"},
|
|
Status: types.StatusSuccess,
|
|
},
|
|
{
|
|
Spec: types.TestSpec{Suite: "Suite1", Name: "TestFailure_Diff"},
|
|
Status: types.StatusFailure,
|
|
Expected: "line1\nline2 expected\nline3",
|
|
Actual: "line1\nline2 actual\nline3",
|
|
},
|
|
{
|
|
Spec: types.TestSpec{Suite: "Suite1", Name: "TestFailure_Message"},
|
|
Status: types.StatusFailure,
|
|
ErrorMessage: "This is a specific failure message.\nWith multiple lines.",
|
|
},
|
|
{
|
|
Spec: types.TestSpec{Suite: "Suite1", Name: "TestError"},
|
|
Status: types.StatusError,
|
|
ErrorMessage: "System error occurred.",
|
|
},
|
|
{
|
|
Spec: types.TestSpec{Suite: "Suite1", Name: "TestEmpty"},
|
|
Status: types.StatusError,
|
|
ErrorMessage: "",
|
|
},
|
|
},
|
|
}
|
|
|
|
stdout, _ := captureOutput(func() {
|
|
PrintErrors(results, true)
|
|
})
|
|
|
|
if strings.Contains(stdout, "TestSuccess") {
|
|
t.Errorf("PrintErrors() should not print success cases, but found 'TestSuccess'")
|
|
}
|
|
|
|
expectedDiffPattern := `\|\s*--- expected\s*\n` + // matches "| --- expected"
|
|
`\|\s*\+\+\+ actual\s*\n` + // matches "| +++ actual"
|
|
`\|\s*@@ -\d+,\d+ \+\d+,\d+ @@\s*\n` + // matches "| @@ <hunk info> @@"
|
|
`\|\s* line1\s*\n` + // matches "| line1" (note the leading space for an "equal" line)
|
|
`\|\s*-line2 expected\s*\n` + // matches "| -line2 expected"
|
|
`\|\s*\+line2 actual\s*\n` + // matches "| +line2 actual"
|
|
`\|\s* line3\s*` // matches "| line3"
|
|
|
|
matched, _ := regexp.MatchString(expectedDiffPattern, stdout)
|
|
|
|
if !matched {
|
|
t.Errorf("PrintErrors() TestFailure_Diff diff output mismatch or missing.\nExpected pattern:\n%s\nGot:\n%s", expectedDiffPattern, stdout)
|
|
}
|
|
|
|
if !strings.Contains(stdout, "⚠ Test \"Suite1/TestFailure_Message\" failed:") {
|
|
t.Errorf("PrintErrors() missing header for TestFailure_Message. Output:\n%s", stdout)
|
|
}
|
|
|
|
if !strings.Contains(stdout, "| This is a specific failure message.") ||
|
|
|
|
!strings.Contains(stdout, "| With multiple lines.") {
|
|
t.Errorf("PrintErrors() TestFailure_Message message output mismatch or missing. Output:\n%s", stdout)
|
|
}
|
|
|
|
if !strings.Contains(stdout, "⚠ Test \"Suite1/TestError\" failed:") {
|
|
t.Errorf("PrintErrors() missing header for TestError. Output:\n%s", stdout)
|
|
}
|
|
|
|
if !strings.Contains(stdout, "| System error occurred.") {
|
|
t.Errorf("PrintErrors() TestError message output mismatch or missing. Output:\n%s", stdout)
|
|
}
|
|
if !strings.Contains(stdout, "- no output -") {
|
|
t.Errorf("PrintErrors() missing '- no output -'. Output:\n%s", stdout)
|
|
}
|
|
}
|
|
|
|
func TestPrintSummary(t *testing.T) {
|
|
text.DisableColors()
|
|
defer text.EnableColors()
|
|
|
|
results := types.Results{
|
|
"AlphaSuite": []types.TestResult{
|
|
{Spec: types.TestSpec{Suite: "AlphaSuite", Name: "TestA", Pos: "alpha.nix:1"}, Status: types.StatusSuccess, Duration: 100 * time.Millisecond},
|
|
{Spec: types.TestSpec{Suite: "AlphaSuite", Name: "TestB", Pos: "alpha.nix:2"}, Status: types.StatusFailure, Duration: 200 * time.Millisecond},
|
|
},
|
|
"BetaSuite": []types.TestResult{
|
|
{Spec: types.TestSpec{Suite: "BetaSuite", Name: "TestC", Pos: "beta.nix:1"}, Status: types.StatusSkipped, Duration: 50 * time.Millisecond},
|
|
{Spec: types.TestSpec{Suite: "BetaSuite", Name: "TestD", Pos: "beta.nix:2"}, Status: types.StatusError, Duration: 150 * time.Millisecond},
|
|
{Spec: types.TestSpec{Suite: "BetaSuite", Name: "TestE", Pos: "beta.nix:3"}, Status: 123, Duration: 150 * time.Millisecond},
|
|
},
|
|
}
|
|
totalSuccessCount := 2
|
|
totalTestCount := 4
|
|
|
|
r, w, _ := os.Pipe()
|
|
originalStdout := os.Stdout
|
|
os.Stdout = w
|
|
|
|
PrintSummary(results, totalSuccessCount, totalTestCount)
|
|
|
|
w.Close()
|
|
os.Stdout = originalStdout
|
|
|
|
var summaryTable bytes.Buffer
|
|
_, _ = io.Copy(&summaryTable, r)
|
|
stdout := summaryTable.String()
|
|
|
|
if !strings.Contains(stdout, "AlphaSuite") || !strings.Contains(stdout, "BetaSuite") {
|
|
t.Errorf("PrintSummary() missing suite names. Output:\n%s", stdout)
|
|
}
|
|
|
|
// check for test names and statuses
|
|
if !strings.Contains(stdout, "TestA") || !strings.Contains(stdout, "PASS") {
|
|
t.Errorf("PrintSummary() missing TestA or its PASS status. Output:\n%s", stdout)
|
|
}
|
|
if !strings.Contains(stdout, "TestB") || !strings.Contains(stdout, "FAIL") {
|
|
t.Errorf("PrintSummary() missing TestB or its FAIL status. Output:\n%s", stdout)
|
|
}
|
|
if !strings.Contains(stdout, "TestE") || !strings.Contains(stdout, "UNKNOWN") {
|
|
t.Errorf("PrintSummary() missing TestE or its UNKNOWN status. Output:\n%s", stdout)
|
|
}
|
|
|
|
// check for total summary
|
|
expectedTotalSummary := fmt.Sprintf("%d/%d (1 SKIPPED)", totalSuccessCount, totalTestCount)
|
|
if !strings.Contains(stdout, expectedTotalSummary) {
|
|
t.Errorf("PrintSummary() total summary incorrect. Expected to contain '%s'. Output:\n%s", expectedTotalSummary, stdout)
|
|
}
|
|
}
|