Skip to content

Commit d0a2a0d

Browse files
committed
v0.3.0 Release: Big bang rewrite using github.com/jessevdk/go-flags
Signed-off-by: Stavros Ntentos <[email protected]>
1 parent 6f2162c commit d0a2a0d

File tree

12 files changed

+203
-124
lines changed

12 files changed

+203
-124
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/stdedos/junit2html
33
go 1.19
44

55
require (
6+
github.com/jessevdk/go-flags v1.6.1
67
github.com/onsi/ginkgo/v2 v2.13.0
78
github.com/stretchr/testify v1.9.0
89
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
@@ -11,5 +12,6 @@ require (
1112
require (
1213
github.com/davecgh/go-spew v1.1.1 // indirect
1314
github.com/pmezard/go-difflib v1.0.0 // indirect
15+
golang.org/x/sys v0.21.0 // indirect
1416
gopkg.in/yaml.v3 v3.0.1 // indirect
1517
)

go.sum

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe
55
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
66
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
77
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
8+
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
9+
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
810
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
911
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
1012
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
@@ -15,7 +17,8 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8
1517
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
1618
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
1719
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
18-
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
20+
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
21+
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1922
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
2023
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
2124
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=

main.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
package main
22

33
import (
4-
"flag"
4+
"os"
55

66
"github.com/stdedos/junit2html/pkg/cmd"
77
)
88

9-
// arguments
10-
var (
11-
xmlReports *string
12-
)
13-
14-
func init() {
15-
xmlReports = flag.String("xmlReports", "", "Comma delimited glob expressions describing the files to scan")
16-
}
17-
189
func main() {
19-
flag.Parse()
20-
cmd.EntryPoint(*xmlReports)
10+
cmd.EntryPoint(os.Args[1:])
2111
}

main_test.go

Lines changed: 34 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3,130 +3,81 @@ package main
33
import (
44
"bytes"
55
"errors"
6-
"fmt"
76
"io"
87
"os"
98
"os/exec"
109
"strings"
1110
"testing"
1211

12+
"github.com/stdedos/junit2html/pkg/cmd"
13+
"github.com/stdedos/junit2html/pkg/utils"
14+
"github.com/stretchr/testify/require"
15+
1316
"github.com/stretchr/testify/assert"
1417
)
1518

1619
const DefaultReport = "examples/junit.xml"
1720

18-
func captureOutput(f func() error) (string, error) {
19-
originalStdout := os.Stdout
20-
r, w, _ := os.Pipe()
21-
os.Stdout = w
22-
defer func() { os.Stdin = originalStdout }()
23-
funcErr := f()
24-
err := w.Close()
25-
if err != nil {
26-
return "", err
27-
}
28-
out, _ := io.ReadAll(r)
29-
return string(out), funcErr
30-
}
31-
32-
func TestMainFunction(t *testing.T) {
21+
func TestMainFunctionViaPipe(t *testing.T) {
3322
var err error
3423

3524
originalStdin := os.Stdin
3625
defer func() { os.Stdin = originalStdin }()
3726
os.Stdin, err = os.Open(DefaultReport)
3827
assert.Nil(t, err)
3928

40-
output, err := captureOutput(func() error {
41-
main()
29+
output, _, err := utils.CaptureOutput(func() error {
30+
// Instead of main, and to avoid playing with arguments,
31+
// we call the entry point directly.
32+
cmd.EntryPoint([]string{})
4233
return nil
4334
})
4435

4536
assert.Contains(t, output, "<html>") // or any expected substring of the output HTML
4637
assert.Nil(t, err)
4738
}
4839

49-
// TestRunMain is a test helper to run the main function.
50-
// Inspiration: https://go.dev/talks/2014/testing.slide#23
51-
func TestRunMain(_ *testing.T) {
40+
// TestMainIsWorking is a test that is used to test the main function.
41+
// Executing a process and passing arguments in Golang is an ordeal;
42+
// We will settle for a simple PoC test (`--help` is passed along).
43+
func TestMainAcceptsArgs(t *testing.T) {
44+
// Inspiration: https://go.dev/talks/2014/testing.slide#23
5245
if os.Getenv("BE_CRASHER") == "1" {
46+
os.Args[1] = "--help"
5347
main()
5448
return
5549
}
56-
}
5750

58-
func TestGlobPattern(t *testing.T) {
59-
cmd := exec.Command(os.Args[0], "-test.run=TestRunMain", "-xmlReports=examples/junit*.xml")
60-
cmd.Env = append(os.Environ(), "BE_CRASHER=1")
51+
proc := exec.Command(os.Args[0], "-test.run=TestMainAcceptsArgs")
52+
proc.Env = append(os.Environ(), "BE_CRASHER=1")
6153

62-
stdoutPipe, err := cmd.StdoutPipe()
63-
if err != nil {
64-
t.Fatalf("Failed to get stdout pipe: %v", err)
65-
}
54+
stdoutPipe, err := proc.StdoutPipe()
55+
require.Nil(t, err, "Failed to get stdout pipe: %v", err)
6656

67-
stderrPipe, err := cmd.StderrPipe()
68-
if err != nil {
69-
t.Fatalf("Failed to get stderr pipe: %v", err)
70-
}
57+
stderrPipe, err := proc.StderrPipe()
58+
require.Nil(t, err, "Failed to get stderr pipe: %v", err)
7159

72-
err = cmd.Start()
73-
assert.Nil(t, err)
60+
err = proc.Start()
61+
require.Nil(t, err)
7462

7563
var stdoutBuf, stderrBuf bytes.Buffer
7664
_, err = io.Copy(&stdoutBuf, stdoutPipe)
77-
if err != nil {
78-
t.Fatalf("Failed to read stdout: %v", err)
79-
}
80-
_, err = io.Copy(&stderrBuf, stderrPipe)
81-
if err != nil {
82-
t.Fatalf("Failed to read stderr: %v", err)
83-
}
84-
85-
var e *exec.ExitError
86-
if errors.As(err, &e) && !e.Success() {
87-
t.Fatalf("process ran with err %v, want exit status 0", err)
88-
}
65+
require.Nil(t, err, "Failed to read stdout: %v", err)
8966

90-
assert.Equal(t, strings.Count(stdoutBuf.String(), "class=\"suites\""), 1)
91-
// 1 argument, 1 files (glob returns 1 file), 1 trailing newline
92-
assert.Equal(t, len(strings.Split(stderrBuf.String(), "\n")), 3)
93-
}
94-
95-
func TestMultiSuite(t *testing.T) {
96-
xmlReportsArg := fmt.Sprintf("-xmlReports=%s,%s", DefaultReport, DefaultReport)
97-
98-
cmd := exec.Command(os.Args[0], "-test.run=TestRunMain", xmlReportsArg)
99-
cmd.Env = append(os.Environ(), "BE_CRASHER=1")
100-
101-
stdoutPipe, err := cmd.StdoutPipe()
102-
if err != nil {
103-
t.Fatalf("Failed to get stdout pipe: %v", err)
104-
}
105-
106-
stderrPipe, err := cmd.StderrPipe()
107-
if err != nil {
108-
t.Fatalf("Failed to get stderr pipe: %v", err)
109-
}
110-
111-
err = cmd.Start()
112-
assert.Nil(t, err)
113-
114-
var stdoutBuf, stderrBuf bytes.Buffer
115-
_, err = io.Copy(&stdoutBuf, stdoutPipe)
116-
if err != nil {
117-
t.Fatalf("Failed to read stdout: %v", err)
118-
}
11967
_, err = io.Copy(&stderrBuf, stderrPipe)
120-
if err != nil {
121-
t.Fatalf("Failed to read stderr: %v", err)
122-
}
68+
require.Nil(t, err, "Failed to read stderr: %v", err)
12369

12470
var e *exec.ExitError
12571
if errors.As(err, &e) && !e.Success() {
126-
t.Fatalf("process ran with err %v, want exit status 0", err)
72+
require.Nil(t, err, "process ran with err %v, want exit status 0", err)
12773
}
12874

129-
assert.Equal(t, strings.Count(stdoutBuf.String(), "class=\"suites\""), 2)
130-
// 2 arguments (as CSV), 2 files (no glob involved), 1 trailing newline
131-
assert.Equal(t, len(strings.Split(stderrBuf.String(), "\n")), 5)
75+
stdoutStr := stdoutBuf.String()
76+
// We asked for help - but it is a bit hard to assert the exact output.
77+
// Let's settle for a few guesses.
78+
assert.GreaterOrEqual(t, len(strings.Split(stdoutStr, "\n")), 10, "Help output heuristic failed: %s", stdoutStr)
79+
assert.True(t, strings.HasPrefix(stdoutStr, "Usage:"), "Help output heuristic failed: %s", stdoutStr)
80+
assert.True(t, strings.Contains(stdoutStr, "Help Options:"), "Help output heuristic failed: %s", stdoutStr)
81+
82+
assert.Equal(t, stderrBuf.String(), "")
13283
}

pkg/cmd/cmd.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,36 @@ package cmd
33
import (
44
"fmt"
55

6+
"github.com/jessevdk/go-flags"
7+
"github.com/stdedos/junit2html/pkg/logging"
8+
69
"github.com/stdedos/junit2html/pkg/convert"
710
"github.com/stdedos/junit2html/pkg/parse"
811
)
912

10-
func EntryPoint(xmlFiles string) {
11-
files := parse.Files(xmlFiles)
13+
type Options struct {
14+
Verbose []bool `short:"v" long:"verbose" description:"Increase verbosity"`
15+
Quiet []bool `short:"q" long:"quiet" description:"Decrease verbosity"`
16+
}
17+
18+
var opts Options
19+
20+
func EntryPoint(args []string) {
21+
positionalArgs, err := flags.ParseArgs(&opts, args)
22+
23+
if flags.WroteHelp(err) {
24+
return
25+
}
26+
27+
if err != nil {
28+
panic(fmt.Errorf("error parsing flags: %w", err))
29+
}
30+
31+
if opts.Verbose != nil || opts.Quiet != nil {
32+
logging.ModifyVerbosity(len(opts.Quiet) - len(opts.Verbose))
33+
}
34+
35+
files := parse.Files(positionalArgs)
1236
suites := parse.Suites(files)
1337

1438
html, err := convert.Convert(suites, files)

pkg/cmd/cmd_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package cmd
2+
3+
import (
4+
"bytes"
5+
"strings"
6+
"testing"
7+
8+
"github.com/stdedos/junit2html/pkg/convert"
9+
"github.com/stdedos/junit2html/pkg/logging"
10+
"github.com/stdedos/junit2html/pkg/utils"
11+
"github.com/stretchr/testify/assert"
12+
"golang.org/x/exp/slog"
13+
)
14+
15+
func TestGlobPattern(t *testing.T) {
16+
origLogger := logging.Logger
17+
defer func() { logging.Logger = origLogger }()
18+
19+
var loggingBuffer bytes.Buffer
20+
21+
logging.SetupLogger(&loggingBuffer)
22+
logging.SetLevel(slog.LevelDebug)
23+
24+
stdoutStr, _, err := utils.CaptureOutput(func() error {
25+
EntryPoint([]string{"junit*.xml"})
26+
return nil
27+
})
28+
assert.Nil(t, err)
29+
30+
assert.Equal(t, strings.Count(stdoutStr, convert.SuitesStartDiv), 1, "stdout heuristic failed: %s", stdoutStr)
31+
32+
// 1 argument, 1 file (glob returns 1 file), 1 trailing newline.
33+
stderrStr := loggingBuffer.String()
34+
assert.Equal(t, len(strings.Split(stderrStr, "\n")), 3, "stderr heuristic failed: %s", stderrStr)
35+
}
36+
37+
func TestMultiSuite(t *testing.T) {
38+
origLogger := logging.Logger
39+
defer func() { logging.Logger = origLogger }()
40+
41+
var loggingBuffer bytes.Buffer
42+
43+
logging.SetupLogger(&loggingBuffer)
44+
logging.SetLevel(slog.LevelDebug)
45+
46+
stdoutStr, _, err := utils.CaptureOutput(func() error {
47+
EntryPoint([]string{"junit.xml", "junit.xml"})
48+
return nil
49+
})
50+
51+
assert.Equal(t, strings.Count(stdoutStr, convert.SuitesStartDiv), 2, "stdout heuristic failed: %s", stdoutStr)
52+
// 2 arguments (as CSV), 2 files (no glob involved), 1 trailing newline.
53+
stderrStr := loggingBuffer.String()
54+
assert.Equal(t, len(strings.Split(stderrStr, "\n")), 5, "stderr heuristic failed: %s", stderrStr)
55+
assert.Nil(t, err)
56+
}

pkg/cmd/junit.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../examples/junit.xml

pkg/convert/convert.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ import (
1111
reporters "github.com/onsi/ginkgo/v2/reporters"
1212
)
1313

14-
const STDIN = "/dev/stdin"
14+
const (
15+
STDIN = "/dev/stdin"
16+
SuitesStartDiv = "<div class=\"suites\">"
17+
)
1518

1619
//go:embed style.css
1720
var styles string
1821

22+
// XXX: That is really not scalable, and it does interfere with the tests.
1923
var output string
2024

2125
func Convert(suitesArray []*reporters.JUnitTestSuites, files []string) (string, error) {
26+
output = ""
2227
output += "<html>"
2328
output += "<head>"
2429
output += "<meta charset=\"UTF-8\">"
@@ -28,7 +33,7 @@ func Convert(suitesArray []*reporters.JUnitTestSuites, files []string) (string,
2833
output += "<h1>Test Results</h1>"
2934

3035
for idxSuite, suites := range suitesArray {
31-
output += "<div class=\"suites\">"
36+
output += SuitesStartDiv
3237
if files[idxSuite] != STDIN {
3338
output += fmt.Sprintf("<h3>Suite Filename</h3><span>%s</span>", files[idxSuite])
3439
}

0 commit comments

Comments
 (0)