diff --git a/cyclonedx.go b/cyclonedx.go index f995afe..cca1f62 100644 --- a/cyclonedx.go +++ b/cyclonedx.go @@ -184,8 +184,8 @@ const ( ) type Dependency struct { - Ref string `xml:"ref,attr"` - Dependencies *[]Dependency `xml:"dependency,omitempty"` + Ref string `json:"ref"` + Dependencies *[]string `json:"dependsOn,omitempty"` } type Diff struct { diff --git a/cyclonedx_json.go b/cyclonedx_json.go index 3efdbde..013578f 100644 --- a/cyclonedx_json.go +++ b/cyclonedx_json.go @@ -19,52 +19,6 @@ package cyclonedx import "encoding/json" -// dependencyJSON is temporarily used for marshalling and unmarshalling Dependency instances to and from JSON -type dependencyJSON struct { - Ref string `json:"ref"` - DependsOn []string `json:"dependsOn,omitempty"` -} - -func (d Dependency) MarshalJSON() ([]byte, error) { - if d.Dependencies == nil || len(*d.Dependencies) == 0 { - return json.Marshal(&dependencyJSON{ - Ref: d.Ref, - }) - } - - dependencyRefs := make([]string, len(*d.Dependencies)) - for i, dependency := range *d.Dependencies { - dependencyRefs[i] = dependency.Ref - } - - return json.Marshal(&dependencyJSON{ - Ref: d.Ref, - DependsOn: dependencyRefs, - }) -} - -func (d *Dependency) UnmarshalJSON(bytes []byte) error { - dependency := new(dependencyJSON) - if err := json.Unmarshal(bytes, dependency); err != nil { - return err - } - d.Ref = dependency.Ref - - if len(dependency.DependsOn) == 0 { - return nil - } - - dependencies := make([]Dependency, len(dependency.DependsOn)) - for i, dep := range dependency.DependsOn { - dependencies[i] = Dependency{ - Ref: dep, - } - } - d.Dependencies = &dependencies - - return nil -} - func (sv SpecVersion) MarshalJSON() ([]byte, error) { return json.Marshal(sv.String()) } diff --git a/cyclonedx_json_test.go b/cyclonedx_json_test.go index 7d0099e..2c09340 100644 --- a/cyclonedx_json_test.go +++ b/cyclonedx_json_test.go @@ -16,62 +16,3 @@ // Copyright (c) OWASP Foundation. All Rights Reserved. package cyclonedx - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDependency_MarshalJSON(t *testing.T) { - // Marshal empty dependency - dependency := Dependency{} - jsonBytes, err := json.Marshal(dependency) - assert.NoError(t, err) - assert.Equal(t, "{\"ref\":\"\"}", string(jsonBytes)) - - // Marshal dependency with empty dependencies - dependency = Dependency{ - Ref: "dependencyRef", - Dependencies: &[]Dependency{}, - } - jsonBytes, err = json.Marshal(dependency) - assert.NoError(t, err) - assert.Equal(t, "{\"ref\":\"dependencyRef\"}", string(jsonBytes)) - - // Marshal dependency with dependencies - dependency = Dependency{ - Ref: "dependencyRef", - Dependencies: &[]Dependency{ - {Ref: "transitiveDependencyRef"}, - }, - } - jsonBytes, err = json.Marshal(dependency) - assert.NoError(t, err) - assert.Equal(t, "{\"ref\":\"dependencyRef\",\"dependsOn\":[\"transitiveDependencyRef\"]}", string(jsonBytes)) -} - -func TestDependency_UnmarshalJSON(t *testing.T) { - // Unmarshal empty dependency - dependency := new(Dependency) - err := json.Unmarshal([]byte("{}"), dependency) - assert.NoError(t, err) - assert.Equal(t, "", dependency.Ref) - assert.Nil(t, dependency.Dependencies) - - // Unmarshal dependency with empty dependencies - dependency = new(Dependency) - err = json.Unmarshal([]byte("{\"ref\":\"dependencyRef\",\"dependsOn\":[]}"), dependency) - assert.NoError(t, err) - assert.Equal(t, "dependencyRef", dependency.Ref) - assert.Nil(t, dependency.Dependencies) - - // Unmarshal dependency with dependencies - dependency = new(Dependency) - err = json.Unmarshal([]byte("{\"ref\":\"dependencyRef\",\"dependsOn\":[\"transitiveDependencyRef\"]}"), dependency) - assert.NoError(t, err) - assert.Equal(t, "dependencyRef", dependency.Ref) - assert.Equal(t, 1, len(*dependency.Dependencies)) - assert.Equal(t, "transitiveDependencyRef", (*dependency.Dependencies)[0].Ref) -} diff --git a/cyclonedx_xml.go b/cyclonedx_xml.go index 83db3c5..655e1bd 100644 --- a/cyclonedx_xml.go +++ b/cyclonedx_xml.go @@ -24,7 +24,8 @@ import ( "io" ) -// bomReferenceXML is temporarily used for marshalling and unmarshalling BOMReference instances to and from XML +// bomReferenceXML is temporarily used for marshalling and unmarshalling +// BOMReference instances to and from XML. type bomReferenceXML struct { Ref string `json:"-" xml:"ref,attr"` } @@ -55,6 +56,47 @@ func (c *Copyright) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { return nil } +// dependencyXML is temporarily used for marshalling and unmarshalling +// Dependency instances to and from XML. +type dependencyXML struct { + Ref string `xml:"ref,attr"` + Dependencies *[]dependencyXML `xml:"dependency,omitempty"` +} + +func (d Dependency) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + xmlDep := dependencyXML{Ref: d.Ref} + + if d.Dependencies != nil && len(*d.Dependencies) > 0 { + xmlDeps := make([]dependencyXML, len(*d.Dependencies)) + for i := range *d.Dependencies { + xmlDeps[i] = dependencyXML{Ref: (*d.Dependencies)[i]} + } + xmlDep.Dependencies = &xmlDeps + } + + return e.EncodeElement(xmlDep, start) +} + +func (d *Dependency) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { + xmlDep := dependencyXML{} + err := dec.DecodeElement(&xmlDep, &start) + if err != nil { + return err + } + + dep := Dependency{Ref: xmlDep.Ref} + if xmlDep.Dependencies != nil && len(*xmlDep.Dependencies) > 0 { + deps := make([]string, len(*xmlDep.Dependencies)) + for i := range *xmlDep.Dependencies { + deps[i] = (*xmlDep.Dependencies)[i].Ref + } + dep.Dependencies = &deps + } + + *d = dep + return nil +} + func (l Licenses) MarshalXML(e *xml.Encoder, start xml.StartElement) error { if len(l) == 0 { return nil diff --git a/cyclonedx_xml_test.go b/cyclonedx_xml_test.go index a7f332e..25c1e4a 100644 --- a/cyclonedx_xml_test.go +++ b/cyclonedx_xml_test.go @@ -79,6 +79,64 @@ func TestCopyright_UnmarshalXML(t *testing.T) { require.Equal(t, "copyright", copyright.Text) } +func TestDependency_MarshalXML(t *testing.T) { + t.Run("Empty", func(t *testing.T) { + dependency := Dependency{} + xmlBytes, err := xml.Marshal(dependency) + require.NoError(t, err) + require.Equal(t, ``, string(xmlBytes)) + }) + + t.Run("EmptyDependencies", func(t *testing.T) { + dependency := Dependency{ + Ref: "dependencyRef", + Dependencies: &[]string{}, + } + xmlBytes, err := xml.Marshal(dependency) + require.NoError(t, err) + require.Equal(t, ``, string(xmlBytes)) + }) + + t.Run("WithDependencies", func(t *testing.T) { + dependency := Dependency{ + Ref: "dependencyRef", + Dependencies: &[]string{ + "transitiveDependencyRef", + }, + } + xmlBytes, err := xml.Marshal(dependency) + require.NoError(t, err) + require.Equal(t, ``, string(xmlBytes)) + }) +} + +func TestDependency_UnmarshalXML(t *testing.T) { + t.Run("Empty", func(t *testing.T) { + dependency := Dependency{} + err := xml.Unmarshal([]byte(``), &dependency) + require.NoError(t, err) + require.Equal(t, "", dependency.Ref) + require.Nil(t, dependency.Dependencies) + }) + + t.Run("EmptyDependencies", func(t *testing.T) { + dependency := Dependency{} + err := xml.Unmarshal([]byte(``), &dependency) + require.NoError(t, err) + require.Equal(t, "dependencyRef", dependency.Ref) + require.Nil(t, dependency.Dependencies) + }) + + t.Run("WithDependencies", func(t *testing.T) { + dependency := Dependency{} + err := xml.Unmarshal([]byte(``), &dependency) + require.NoError(t, err) + require.Equal(t, "dependencyRef", dependency.Ref) + require.Equal(t, 1, len(*dependency.Dependencies)) + require.Equal(t, "transitiveDependencyRef", (*dependency.Dependencies)[0]) + }) +} + func TestLicenses_MarshalXML(t *testing.T) { // Marshal license and expressions licenses := Licenses{ diff --git a/example_test.go b/example_test.go index 4b7e64a..f52d7de 100644 --- a/example_test.go +++ b/example_test.go @@ -64,8 +64,8 @@ func Example_encode() { dependencies := []cdx.Dependency{ { Ref: "pkg:golang/acme-inc/acme-app@v1.0.0", - Dependencies: &[]cdx.Dependency{ - {Ref: "pkg:golang/github.com/CycloneDX/cyclonedx-go@v0.3.0"}, + Dependencies: &[]string{ + "pkg:golang/github.com/CycloneDX/cyclonedx-go@v0.3.0", }, }, { diff --git a/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-dependency.json b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-dependency.json index 4ca67e9..a908a7b 100644 --- a/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-dependency.json +++ b/testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-dependency.json @@ -25,7 +25,8 @@ ], "dependencies": [ { - "ref": "library-a" + "ref": "library-a", + "dependsOn": [] }, { "ref": "library-b",