github.com/nozzle/golangci-lint@v1.49.0-nz3/pkg/printers/junitxml.go (about)

     1  package printers
     2  
     3  import (
     4  	"context"
     5  	"encoding/xml"
     6  	"fmt"
     7  	"io"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/golangci/golangci-lint/pkg/result"
    12  )
    13  
    14  type testSuitesXML struct {
    15  	XMLName    xml.Name `xml:"testsuites"`
    16  	TestSuites []testSuiteXML
    17  }
    18  
    19  type testSuiteXML struct {
    20  	XMLName   xml.Name      `xml:"testsuite"`
    21  	Suite     string        `xml:"name,attr"`
    22  	Tests     int           `xml:"tests,attr"`
    23  	Errors    int           `xml:"errors,attr"`
    24  	Failures  int           `xml:"failures,attr"`
    25  	TestCases []testCaseXML `xml:"testcase"`
    26  }
    27  
    28  type testCaseXML struct {
    29  	Name      string     `xml:"name,attr"`
    30  	ClassName string     `xml:"classname,attr"`
    31  	Failure   failureXML `xml:"failure"`
    32  }
    33  
    34  type failureXML struct {
    35  	Message string `xml:"message,attr"`
    36  	Type    string `xml:"type,attr"`
    37  	Content string `xml:",cdata"`
    38  }
    39  
    40  type JunitXML struct {
    41  	w io.Writer
    42  }
    43  
    44  func NewJunitXML(w io.Writer) *JunitXML {
    45  	return &JunitXML{w: w}
    46  }
    47  
    48  func (p JunitXML) Print(ctx context.Context, issues []result.Issue) error {
    49  	suites := make(map[string]testSuiteXML) // use a map to group by file
    50  
    51  	for ind := range issues {
    52  		i := &issues[ind]
    53  		suiteName := i.FilePath()
    54  		testSuite := suites[suiteName]
    55  		testSuite.Suite = i.FilePath()
    56  		testSuite.Tests++
    57  		testSuite.Failures++
    58  
    59  		tc := testCaseXML{
    60  			Name:      i.FromLinter,
    61  			ClassName: i.Pos.String(),
    62  			Failure: failureXML{
    63  				Type:    i.Severity,
    64  				Message: i.Pos.String() + ": " + i.Text,
    65  				Content: fmt.Sprintf("%s: %s\nCategory: %s\nFile: %s\nLine: %d\nDetails: %s",
    66  					i.Severity, i.Text, i.FromLinter, i.Pos.Filename, i.Pos.Line, strings.Join(i.SourceLines, "\n")),
    67  			},
    68  		}
    69  
    70  		testSuite.TestCases = append(testSuite.TestCases, tc)
    71  		suites[suiteName] = testSuite
    72  	}
    73  
    74  	var res testSuitesXML
    75  	for _, val := range suites {
    76  		res.TestSuites = append(res.TestSuites, val)
    77  	}
    78  
    79  	sort.Slice(res.TestSuites, func(i, j int) bool {
    80  		return res.TestSuites[i].Suite < res.TestSuites[j].Suite
    81  	})
    82  
    83  	enc := xml.NewEncoder(p.w)
    84  	enc.Indent("", "  ")
    85  	if err := enc.Encode(res); err != nil {
    86  		return err
    87  	}
    88  	return nil
    89  }