Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom attributes in junit.Testcase (and other types potentially) #18

Open
jgold2-stripe opened this issue Jul 5, 2024 · 0 comments

Comments

@jgold2-stripe
Copy link

We have systems that extend the Junit data model, adding some custom attributes which are discussed elsewhere in the community, such as assertions (specified in places like this "spec" for jenkins or this XSD schema), as well as other attributes that are specific to our company.

We would like to use the junit package here and its associated types, but need a way to add support for handling our custom attributes. I have an approach I could propose, so want to check here before sending a PR.

Option (1) involves adding a new field to types like Testcase:

type Testcase struct {
  // ... existing fields unchanged
  CustomAttrs map[xml.Name]string `xml:"-"`
}

func (c *Testcase) MarshalXML(...) {
  // add `CustomAttrs` to the outbound element and then marshal as we currently do
}

func (c *Testcase) UnmarshalXML(...) {
  // populate `CustomAttrs` with all or just the custom ones from the inbound element,
  // then unmarshal the rest as we currently do
}

Option (2) involves allowing callers to create their own custom type, typically derived from Testcase, which includes additional attributes:

package main

// This is just a sketch of something which would be properly implemented and
// tested in a PR

import (
	"encoding/xml"
	"log"
	"reflect"
)

type Testcase struct {
	Name string `xml:"name,attr"`

	// Rest of fields as usual
}

type Testsuite[TestcaseType any] struct {
	Testcases []TestcaseType `xml:"testcase,omitempty"`

	// Rest of fields as usual
}

type customTestcase struct {
	Testcase
	Assertions int `xml:"assertions,omitempty,attr"`
}

func main() {
	suite := Testsuite[customTestcase]{
		Testcases: []customTestcase{
			{
				Testcase: Testcase{
					Name: "test1",
				},
			},
			{
				Testcase: Testcase{
					Name: "test2",
				},
				Assertions: 4242,
			},
		},
	}
	b, err := xml.MarshalIndent(&suite, "", "    ")
	if err != nil {
		log.Fatal("xml.Marshal: %s", err)
	}
	log.Printf("marshalled:\n%s", b)
	var suite2 Testsuite[customTestcase]
	if err := xml.Unmarshal(b, &suite2); err != nil {
		log.Fatal("xml.Unmarshal: %s", err)
	}
	if !reflect.DeepEqual(&suite, &suite2) {
		log.Fatal("reflect.DeepEqual is false")
	}
	log.Printf("roundtripped successfully")
}

There are tradeoffs. With (1) we can support arbitrary attributes but in an untyped manner. With (2) we can let users (like us) strongly type their custom attributes, but the introduction of generics could represent a breaking change to other projects.

We're happy with either version though, so let me know if you would accept a PR and, if so, which version (or some alternate you have in mind).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant