From bb3ad9fc17caf091406bdab0556ac1fcff8c29f6 Mon Sep 17 00:00:00 2001 From: Tomasz Janiszewski Date: Thu, 4 Aug 2022 11:30:27 +0200 Subject: [PATCH 1/5] Drop control characters from output Fixes: https://github.com/jstemmer/go-junit-report/issues/138 --- parser/gotest/internal/collector/collector.go | 17 ++++++++++++++--- .../internal/collector/collector_test.go | 9 +++++++++ testdata/035-report.xml | 12 ++++++++++-- testdata/035-whitespace.txt | Bin 2224 -> 2470 bytes testdata/src/whitespace/whitespace_test.go | 6 ++++++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/parser/gotest/internal/collector/collector.go b/parser/gotest/internal/collector/collector.go index 92d5e1ff..1d856084 100644 --- a/parser/gotest/internal/collector/collector.go +++ b/parser/gotest/internal/collector/collector.go @@ -4,13 +4,24 @@ package collector import ( "sort" + "strings" "time" + "unicode" ) // line is a single line of output captured at some point in time. type line struct { Timestamp time.Time - Text string + text string +} + +func (l line) SafeText() string { + return strings.Map(func(r rune) rune { + if unicode.IsControl(r) && !unicode.IsSpace(r) { + return -1 + } + return r + }, l.text) } // Output stores output lines grouped by id. Output can be retrieved for one or @@ -54,7 +65,7 @@ func (o *Output) Contains(id int) bool { func (o *Output) Get(id int) []string { var lines []string for _, line := range o.m[id] { - lines = append(lines, line.Text) + lines = append(lines, line.SafeText()) } return lines } @@ -71,7 +82,7 @@ func (o *Output) GetAll(ids ...int) []string { }) var lines []string for _, line := range output { - lines = append(lines, line.Text) + lines = append(lines, line.SafeText()) } return lines } diff --git a/parser/gotest/internal/collector/collector_test.go b/parser/gotest/internal/collector/collector_test.go index bfad6f93..95ee9274 100644 --- a/parser/gotest/internal/collector/collector_test.go +++ b/parser/gotest/internal/collector/collector_test.go @@ -115,3 +115,12 @@ func TestActiveID(t *testing.T) { } } + +func TestSafeText(t *testing.T) { + l := line{text: "\tx\x00y\x1bz\n"} + got := l.SafeText() + want := "\txyz\n" + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("SafeText() for %q incorrect (-want +got):\n%s", l.text, diff) + } +} diff --git a/testdata/035-report.xml b/testdata/035-report.xml index db1a68cc..70b972c5 100644 --- a/testdata/035-report.xml +++ b/testdata/035-report.xml @@ -1,6 +1,6 @@ - - + + @@ -45,6 +45,10 @@ one-newline two-newlines two-newlines two-newlines]]> + + + @@ -89,5 +93,9 @@ two-newlines two-newlines two-newlines]]> + + + diff --git a/testdata/035-whitespace.txt b/testdata/035-whitespace.txt index 7d6590ca4d88e751e4be187624dae8c52f9378fe..544a4041dfaaca3c810925bfca270d0550046c7e 100644 GIT binary patch delta 158 zcmdlWxJ-D%UuJga{JfH){G7=b*(7Z(trT+d(-{ Date: Tue, 16 Aug 2022 11:50:38 +0200 Subject: [PATCH 2/5] Use xml.EscapeText --- junit/junit.go | 15 +++++++++++++-- junit/junit_test.go | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/junit/junit.go b/junit/junit.go index be0313a3..57f83046 100644 --- a/junit/junit.go +++ b/junit/junit.go @@ -3,6 +3,7 @@ package junit import ( + "bytes" "encoding/xml" "fmt" "strings" @@ -235,6 +236,16 @@ func formatDuration(d time.Duration) string { } // formatOutput combines the lines from the given output into a single string. -func formatOutput(output []string) string { - return strings.Join(output, "\n") +func formatOutput(output []string, _ int) string { + buf := bytes.NewBufferString("") + for i, o := range output { + err := xml.EscapeText(buf, []byte(o)) + if err != nil { + return "formatOutput: " + err.Error() + } + if i < len(output)-1 { + buf.WriteString("\n") + } + } + return buf.String() } diff --git a/junit/junit_test.go b/junit/junit_test.go index a19478cb..4e7f71b7 100644 --- a/junit/junit_test.go +++ b/junit/junit_test.go @@ -26,6 +26,11 @@ func TestCreateFromReport(t *testing.T) { Result: gtr.Pass, Output: []string{"ok"}, }, + { + Name: "TestEscapeOutput", + Result: gtr.Pass, + Output: []string{"\x00\v\f \t\\"}, + }, { Name: "TestFail", Result: gtr.Fail, @@ -47,14 +52,14 @@ func TestCreateFromReport(t *testing.T) { } want := Testsuites{ - Tests: 6, + Tests: 7, Errors: 3, Failures: 1, Skipped: 1, Suites: []Testsuite{ { Name: "package/name", - Tests: 6, + Tests: 7, Errors: 3, ID: 0, Failures: 1, @@ -72,6 +77,12 @@ func TestCreateFromReport(t *testing.T) { Time: "0.000", SystemOut: &Output{Data: "ok"}, }, + { + Name: "TestEscapeOutput", + Classname: "package/name", + Time: "0.000", + SystemOut: &Output{Data: `��� \`}, + }, { Name: "TestFail", Classname: "package/name", From 517787cb34176fd7eda5466627d04dedbba694cc Mon Sep 17 00:00:00 2001 From: Tomasz Janiszewski Date: Tue, 16 Aug 2022 11:50:56 +0200 Subject: [PATCH 3/5] Revert "Drop control characters from output" This reverts commit bc70670a401d5123cafab4aa5fbc988e6bf742f6. --- parser/gotest/internal/collector/collector.go | 17 +++-------------- testdata/035-report.xml | 12 ++---------- testdata/035-whitespace.txt | Bin 2470 -> 2224 bytes testdata/src/whitespace/whitespace_test.go | 6 ------ 4 files changed, 5 insertions(+), 30 deletions(-) diff --git a/parser/gotest/internal/collector/collector.go b/parser/gotest/internal/collector/collector.go index 1d856084..92d5e1ff 100644 --- a/parser/gotest/internal/collector/collector.go +++ b/parser/gotest/internal/collector/collector.go @@ -4,24 +4,13 @@ package collector import ( "sort" - "strings" "time" - "unicode" ) // line is a single line of output captured at some point in time. type line struct { Timestamp time.Time - text string -} - -func (l line) SafeText() string { - return strings.Map(func(r rune) rune { - if unicode.IsControl(r) && !unicode.IsSpace(r) { - return -1 - } - return r - }, l.text) + Text string } // Output stores output lines grouped by id. Output can be retrieved for one or @@ -65,7 +54,7 @@ func (o *Output) Contains(id int) bool { func (o *Output) Get(id int) []string { var lines []string for _, line := range o.m[id] { - lines = append(lines, line.SafeText()) + lines = append(lines, line.Text) } return lines } @@ -82,7 +71,7 @@ func (o *Output) GetAll(ids ...int) []string { }) var lines []string for _, line := range output { - lines = append(lines, line.SafeText()) + lines = append(lines, line.Text) } return lines } diff --git a/testdata/035-report.xml b/testdata/035-report.xml index 70b972c5..db1a68cc 100644 --- a/testdata/035-report.xml +++ b/testdata/035-report.xml @@ -1,6 +1,6 @@ - - + + @@ -45,10 +45,6 @@ one-newline two-newlines two-newlines two-newlines]]> - - - @@ -93,9 +89,5 @@ two-newlines two-newlines two-newlines]]> - - - diff --git a/testdata/035-whitespace.txt b/testdata/035-whitespace.txt index 544a4041dfaaca3c810925bfca270d0550046c7e..7d6590ca4d88e751e4be187624dae8c52f9378fe 100644 GIT binary patch delta 28 kcmZ1`yg_ioU*^dTEF7B)S(Y$QKEcd4xsK!N Date: Thu, 15 Sep 2022 10:56:56 +0200 Subject: [PATCH 4/5] Allow whitespaces --- junit/junit.go | 37 +++++++++++++------ junit/junit_test.go | 2 +- .../internal/collector/collector_test.go | 9 ----- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/junit/junit.go b/junit/junit.go index 57f83046..80c68b3e 100644 --- a/junit/junit.go +++ b/junit/junit.go @@ -3,11 +3,11 @@ package junit import ( - "bytes" "encoding/xml" "fmt" "strings" "time" + "unicode" "github.com/jstemmer/go-junit-report/v2/gtr" ) @@ -236,16 +236,31 @@ func formatDuration(d time.Duration) string { } // formatOutput combines the lines from the given output into a single string. -func formatOutput(output []string, _ int) string { - buf := bytes.NewBufferString("") - for i, o := range output { - err := xml.EscapeText(buf, []byte(o)) - if err != nil { - return "formatOutput: " + err.Error() +func formatOutput(output []string) string { + return escapeIllegalChars(strings.Join(output, "\n")) +} + +func escapeIllegalChars(str string) string { + return strings.Map(func(r rune) rune { + if unicode.IsSpace(r) { + return r } - if i < len(output)-1 { - buf.WriteString("\n") + if isInCharacterRange(r) { + return r } - } - return buf.String() + return '�' + }, str) +} + +// Decide whether the given rune is in the XML Character Range, per +// the Char production of https://www.xml.com/axml/testaxml.htm, +// Section 2.2 Characters. +// Form: encoding/xml/xml.go +func isInCharacterRange(r rune) (inrange bool) { + return r == 0x09 || + r == 0x0A || + r == 0x0D || + r >= 0x20 && r <= 0xD7FF || + r >= 0xE000 && r <= 0xFFFD || + r >= 0x10000 && r <= 0x10FFFF } diff --git a/junit/junit_test.go b/junit/junit_test.go index 4e7f71b7..ab9e53a0 100644 --- a/junit/junit_test.go +++ b/junit/junit_test.go @@ -81,7 +81,7 @@ func TestCreateFromReport(t *testing.T) { Name: "TestEscapeOutput", Classname: "package/name", Time: "0.000", - SystemOut: &Output{Data: `��� \`}, + SystemOut: &Output{Data: "�\v\f \t\\"}, }, { Name: "TestFail", diff --git a/parser/gotest/internal/collector/collector_test.go b/parser/gotest/internal/collector/collector_test.go index 95ee9274..bfad6f93 100644 --- a/parser/gotest/internal/collector/collector_test.go +++ b/parser/gotest/internal/collector/collector_test.go @@ -115,12 +115,3 @@ func TestActiveID(t *testing.T) { } } - -func TestSafeText(t *testing.T) { - l := line{text: "\tx\x00y\x1bz\n"} - got := l.SafeText() - want := "\txyz\n" - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("SafeText() for %q incorrect (-want +got):\n%s", l.text, diff) - } -} From c585335c894c227acb39923eff72e3c92cf0c501 Mon Sep 17 00:00:00 2001 From: Tomasz Janiszewski Date: Fri, 16 Sep 2022 11:24:25 +0200 Subject: [PATCH 5/5] Do not include \v\f\r --- junit/junit.go | 4 ---- junit/junit_test.go | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/junit/junit.go b/junit/junit.go index 80c68b3e..65117a23 100644 --- a/junit/junit.go +++ b/junit/junit.go @@ -7,7 +7,6 @@ import ( "fmt" "strings" "time" - "unicode" "github.com/jstemmer/go-junit-report/v2/gtr" ) @@ -242,9 +241,6 @@ func formatOutput(output []string) string { func escapeIllegalChars(str string) string { return strings.Map(func(r rune) rune { - if unicode.IsSpace(r) { - return r - } if isInCharacterRange(r) { return r } diff --git a/junit/junit_test.go b/junit/junit_test.go index ab9e53a0..4c51c764 100644 --- a/junit/junit_test.go +++ b/junit/junit_test.go @@ -81,7 +81,7 @@ func TestCreateFromReport(t *testing.T) { Name: "TestEscapeOutput", Classname: "package/name", Time: "0.000", - SystemOut: &Output{Data: "�\v\f \t\\"}, + SystemOut: &Output{Data: `��� \`}, }, { Name: "TestFail",