Skip to content

Commit

Permalink
Refactor to enable ingesting a reader directly (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshdk committed Oct 27, 2019
1 parent f9efe7c commit 93e3ed9
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 17 deletions.
22 changes: 15 additions & 7 deletions ingesters.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
package junit

import (
"io/ioutil"
"bytes"
"io"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -55,23 +56,24 @@ func IngestFiles(filenames []string) ([]Suite, error) {
// IngestFile will parse the given XML file and return a slice of all contained
// JUnit test suite definitions.
func IngestFile(filename string) ([]Suite, error) {
data, err := ioutil.ReadFile(filename)
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()

return Ingest(data)
return IngestReader(file)
}

// Ingest will parse the given XML data and return a slice of all contained
// JUnit test suite definitions.
func Ingest(data []byte) ([]Suite, error) {
// IngestReader will parse the given XML reader and return a slice of all
// contained JUnit test suite definitions.
func IngestReader(reader io.Reader) ([]Suite, error) {
var (
suiteChan = make(chan Suite)
suites = make([]Suite, 0)
)

nodes, err := parse(data)
nodes, err := parse(reader)
if err != nil {
return nil, err
}
Expand All @@ -87,3 +89,9 @@ func Ingest(data []byte) ([]Suite, error) {

return suites, nil
}

// Ingest will parse the given XML data and return a slice of all contained
// JUnit test suite definitions.
func Ingest(data []byte) ([]Suite, error) {
return IngestReader(bytes.NewReader(data))
}
18 changes: 11 additions & 7 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,24 @@ import (
"encoding/xml"
"errors"
"html"
"io"
)

// reparentXML will wrap the given data (which is assumed to be valid XML), in
// a fake root nodeAlias.
// reparentXML will wrap the given reader (which is assumed to be valid XML),
// in a fake root nodeAlias.
//
// This action is useful in the event that the original XML document does not
// have a single root nodeAlias, which is required by the XML specification.
// Additionally, Go's XML parser will silently drop all nodes after the first
// that is encountered, which can lead to data loss from a parser perspective.
// This function also enables the ingestion of blank XML files, which would
// normally cause a parsing error.
func reparentXML(data []byte) []byte {
return append(append([]byte("<fake-root>"), data...), "</fake-root>"...)
func reparentXML(reader io.Reader) io.Reader {
return io.MultiReader(
bytes.NewReader([]byte("<fake-root>")),
reader,
bytes.NewReader([]byte("</fake-root>")),
)
}

// extractContent parses the raw contents from an XML node, and returns it in a
Expand Down Expand Up @@ -96,10 +101,9 @@ func extractContent(data []byte) ([]byte, error) {

// parse unmarshalls the given XML data into a graph of nodes, and then returns
// a slice of all top-level nodes.
func parse(data []byte) ([]xmlNode, error) {
func parse(reader io.Reader) ([]xmlNode, error) {
var (
buf = bytes.NewBuffer(reparentXML(data))
dec = xml.NewDecoder(buf)
dec = xml.NewDecoder(reparentXML(reader))
root xmlNode
)

Expand Down
9 changes: 6 additions & 3 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
package junit

import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -39,7 +41,9 @@ func TestReparent(t *testing.T) {
name := fmt.Sprintf("#%d - %s", index+1, test.title)

t.Run(name, func(t *testing.T) {
actual := reparentXML(test.input)
reader := reparentXML(bytes.NewReader(test.input))
actual, err := ioutil.ReadAll(reader)
assert.NoError(t, err)

assert.Equal(t, test.expected, string(actual))
})
Expand Down Expand Up @@ -168,8 +172,7 @@ func TestParse(t *testing.T) {
name := fmt.Sprintf("#%d - %s", index+1, test.title)

t.Run(name, func(t *testing.T) {
actual, err := parse(test.input)

actual, err := parse(bytes.NewReader(test.input))
require.Nil(t, err)

assert.Equal(t, test.expected, actual)
Expand Down

0 comments on commit 93e3ed9

Please sign in to comment.