Skip to content

Commit

Permalink
Split generated code and generated tests into separate files
Browse files Browse the repository at this point in the history
  • Loading branch information
droyo committed Jan 3, 2019
1 parent 30b6a87 commit 0880b4c
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 175 deletions.
102 changes: 59 additions & 43 deletions gentests/_testgen/testgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,25 @@ func glob(pat string) string {
func main() {
var errorsEncountered bool
cfg := new(xsdgen.Config)
cases := findXSDTestCases()

xsdTestCases, err := findXSDTestCases()
if err != nil {
log.Fatal(err)
}

cfg.Option(xsdgen.DefaultOptions...)
for _, dir := range cases {
data, err := ioutil.ReadFile(glob(filepath.Join(dir, "*.xsd")))
for _, testCase := range xsdTestCases {
code, tests, err := genXSDTests(*cfg, testCase.doc, testCase.pkg)
if err != nil {
errorsEncountered = true
log.Print(err)
continue
}
tests, err := genXSDTests(*cfg, data, dir)
if err != nil {
errorsEncountered = true
log.Print(dir, ":", err)
log.Print(testCase.pkg)
continue
} else {
log.Printf("generated xsd tests for %s", dir)
log.Printf("generated xsd tests for %s", testCase.pkg)
}
if err := writeTestFiles(tests, dir); err != nil {
if err := writeTestFiles(code, tests, testCase.pkg); err != nil {
errorsEncountered = true
log.Print(dir, ":", err)
log.Print(testCase.pkg, ":", err)
}
}

Expand All @@ -61,20 +59,22 @@ func main() {
}
}

func writeTestFiles(file *ast.File, pkg string) error {
func writeTestFiles(code, tests *ast.File, pkg string) error {
testFilename := filepath.Join(pkg, pkg+"_test.go")

src, err := gen.FormattedSource(file, testFilename)
testSrc, err := gen.FormattedSource(tests, testFilename)
if err != nil {
return err
}
if err := ioutil.WriteFile(testFilename, src, 0666); err != nil {
if err := ioutil.WriteFile(testFilename, testSrc, 0666); err != nil {
return err
}

// This is needed so 'go build' works and automated CI doesn't complain.
buildFilename := filepath.Join(pkg, pkg+".go")
return ioutil.WriteFile(buildFilename, []byte("package "+pkg+"\n"), 0666)
codeFilename := filepath.Join(pkg, pkg+".go")
codeSrc, err := gen.FormattedSource(code, codeFilename)
if err != nil {
return err
}
return ioutil.WriteFile(codeFilename, codeSrc, 0666)
}

// Generates unit tests for xml marshal unmarshalling of
Expand All @@ -85,25 +85,30 @@ func writeTestFiles(file *ast.File, pkg string) error {
// the document described in the XML schema.
// - Marshal the resulting file back into an XML document.
// - Compare the two documents for equality.
func genXSDTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error) {
cfg.Option(xsdgen.PackageName(dir))
code, err := cfg.GenCode(data)
//
// Returns type definitions and unit tests as separate files.
func genXSDTests(cfg xsdgen.Config, data []byte, pkg string) (code, tests *ast.File, err error) {
cfg.Option(xsdgen.PackageName(pkg))
main, err := cfg.GenCode(data)
if err != nil {
return nil, err
return nil, nil, err
}
file, err := code.GenAST()
code, err = main.GenAST()
if err != nil {
return nil, err
return nil, nil, err
}

tests = new(ast.File)
tests.Name = ast.NewIdent(pkg)

// We look for top-level elements in the schema to determine what
// the example document looks like.
roots, err := xsd.Normalize(data)
if err != nil {
return nil, err
return nil, nil, err
}
if len(roots) < 1 {
return nil, fmt.Errorf("no schema in %s", dir)
return nil, nil, fmt.Errorf("no schema in %s", pkg)
}
root := roots[0]
doc := topLevelElements(root)
Expand All @@ -112,21 +117,21 @@ func genXSDTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error)
for _, elem := range doc {
fields = append(fields,
gen.Public(elem.Name.Local),
ast.NewIdent(code.NameOf(elem.Type)),
ast.NewIdent(main.NameOf(elem.Type)),
gen.String(fmt.Sprintf(`xml:"%s %s"`, elem.Name.Space, elem.Name.Local)))
}
expr, err := gen.ToString(gen.Struct(fields...))
if err != nil {
return nil, err
return nil, nil, err
}

var params struct {
DocStruct string
Dir string
Pkg string
}
params.DocStruct = expr
params.Dir = dir
fn, err := gen.Func("Test"+strings.Title(dir)).
params.Pkg = pkg
fn, err := gen.Func("Test"+strings.Title(pkg)).
Args("t *testing.T").
BodyTmpl(`
type Document {{.DocStruct}}
Expand Down Expand Up @@ -155,7 +160,7 @@ func genXSDTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error)
inputTree, err := xmltree.Parse(input)
if err != nil {
t.Fatal("{{.Dir}}: ", err)
t.Fatal("{{.Pkg}}: ", err)
}
outputTree, err := xmltree.Parse(output)
Expand All @@ -171,11 +176,10 @@ func genXSDTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error)
`, params).Decl()

if err != nil {
return nil, err
return nil, nil, err
}
// Test goes at the top
file.Decls = append([]ast.Decl{fn}, file.Decls...)
return file, nil
tests.Decls = append(tests.Decls, fn)
return code, tests, nil
}

type Element struct {
Expand All @@ -201,17 +205,29 @@ func topLevelElements(root *xmltree.Element) []Element {
return result
}

type testCase struct {
pkg string
doc []byte
}

// Looks for subdirectories containing pairs of (xml, xsd) files
// that should contain an xml document and the schema it conforms to,
// respectively. Returns slice of the directory names
func findXSDTestCases() []string {
func findXSDTestCases() ([]testCase, error) {
filenames, err := filepath.Glob("*/*.xsd")
if err != nil {
return nil
return nil, err
}
result := make([]string, 0, len(filenames))
result := make([]testCase, 0, len(filenames))
for _, xsdfile := range filenames {
result = append(result, filepath.Base(filepath.Dir(xsdfile)))
if data, err := ioutil.ReadFile(xsdfile); err != nil {
return nil, err
} else {
result = append(result, testCase{
pkg: filepath.Base(filepath.Dir(xsdfile)),
doc: data,
})
}
}
return result
return result, nil
}
65 changes: 65 additions & 0 deletions gentests/bindata/bindata.go
Original file line number Diff line number Diff line change
@@ -1 +1,66 @@
package bindata

import (
"bytes"
"encoding/base64"
"encoding/hex"
"encoding/xml"
)

type Bindata struct {
HexData []byte `xml:"tns hexData"`
B64Data []byte `xml:"tns b64Data"`
Filename string `xml:"tns filename"`
}

func (t *Bindata) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
type T Bindata
var layout struct {
*T
HexData *xsdHexBinary `xml:"tns hexData"`
B64Data *xsdBase64Binary `xml:"tns b64Data"`
}
layout.T = (*T)(t)
layout.HexData = (*xsdHexBinary)(&layout.T.HexData)
layout.B64Data = (*xsdBase64Binary)(&layout.T.B64Data)
return e.EncodeElement(layout, start)
}
func (t *Bindata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type T Bindata
var overlay struct {
*T
HexData *xsdHexBinary `xml:"tns hexData"`
B64Data *xsdBase64Binary `xml:"tns b64Data"`
}
overlay.T = (*T)(t)
overlay.HexData = (*xsdHexBinary)(&overlay.T.HexData)
overlay.B64Data = (*xsdBase64Binary)(&overlay.T.B64Data)
return d.DecodeElement(&overlay, &start)
}

type xsdBase64Binary []byte

func (b *xsdBase64Binary) UnmarshalText(text []byte) (err error) {
*b, err = base64.StdEncoding.DecodeString(string(text))
return
}
func (b xsdBase64Binary) MarshalText() ([]byte, error) {
var buf bytes.Buffer
enc := base64.NewEncoder(base64.StdEncoding, &buf)
enc.Write([]byte(b))
enc.Close()
return buf.Bytes(), nil
}

type xsdHexBinary []byte

func (b *xsdHexBinary) UnmarshalText(text []byte) (err error) {
*b, err = hex.DecodeString(string(text))
return
}
func (b xsdHexBinary) MarshalText() ([]byte, error) {
n := hex.EncodedLen(len(b))
buf := make([]byte, n)
hex.Encode(buf, []byte(b))
return buf, nil
}
61 changes: 0 additions & 61 deletions gentests/bindata/bindata_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package bindata

import (
"bytes"
"encoding/base64"
"encoding/hex"
"encoding/xml"
"io/ioutil"
"path/filepath"
Expand Down Expand Up @@ -49,61 +46,3 @@ func TestBindata(t *testing.T) {
t.Errorf("got \n%s\n, wanted \n%s\n", xmltree.MarshalIndent(outputTree, "", " "), xmltree.MarshalIndent(inputTree, "", " "))
}
}

type Bindata struct {
HexData []byte `xml:"tns hexData"`
B64Data []byte `xml:"tns b64Data"`
Filename string `xml:"tns filename"`
}

func (t *Bindata) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
type T Bindata
var layout struct {
*T
HexData *xsdHexBinary `xml:"tns hexData"`
B64Data *xsdBase64Binary `xml:"tns b64Data"`
}
layout.T = (*T)(t)
layout.HexData = (*xsdHexBinary)(&layout.T.HexData)
layout.B64Data = (*xsdBase64Binary)(&layout.T.B64Data)
return e.EncodeElement(layout, start)
}
func (t *Bindata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type T Bindata
var overlay struct {
*T
HexData *xsdHexBinary `xml:"tns hexData"`
B64Data *xsdBase64Binary `xml:"tns b64Data"`
}
overlay.T = (*T)(t)
overlay.HexData = (*xsdHexBinary)(&overlay.T.HexData)
overlay.B64Data = (*xsdBase64Binary)(&overlay.T.B64Data)
return d.DecodeElement(&overlay, &start)
}

type xsdBase64Binary []byte

func (b *xsdBase64Binary) UnmarshalText(text []byte) (err error) {
*b, err = base64.StdEncoding.DecodeString(string(text))
return
}
func (b xsdBase64Binary) MarshalText() ([]byte, error) {
var buf bytes.Buffer
enc := base64.NewEncoder(base64.StdEncoding, &buf)
enc.Write([]byte(b))
enc.Close()
return buf.Bytes(), nil
}

type xsdHexBinary []byte

func (b *xsdHexBinary) UnmarshalText(text []byte) (err error) {
*b, err = hex.DecodeString(string(text))
return
}
func (b xsdHexBinary) MarshalText() ([]byte, error) {
n := hex.EncodedLen(len(b))
buf := make([]byte, n)
hex.Encode(buf, []byte(b))
return buf, nil
}
Loading

0 comments on commit 0880b4c

Please sign in to comment.