Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: prevent nesting of Dependency
BREAKING-CHANGE: the type of `Dependency.Dependencies` has changed from `*[]Dependency` to `*[]string`

fixes #36

Signed-off-by: nscuro <nscuro@protonmail.com>
  • Loading branch information
nscuro committed Sep 26, 2022
1 parent 3390ca4 commit ea0d5b7
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 111 deletions.
4 changes: 2 additions & 2 deletions cyclonedx.go
Expand Up @@ -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 {
Expand Down
46 changes: 0 additions & 46 deletions cyclonedx_json.go
Expand Up @@ -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())
}
Expand Down
59 changes: 0 additions & 59 deletions cyclonedx_json_test.go
Expand Up @@ -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)
}
44 changes: 43 additions & 1 deletion cyclonedx_xml.go
Expand Up @@ -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"`
}
Expand Down Expand Up @@ -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
Expand Down
58 changes: 58 additions & 0 deletions cyclonedx_xml_test.go
Expand Up @@ -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, `<Dependency ref=""></Dependency>`, 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, `<Dependency ref="dependencyRef"></Dependency>`, 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, `<Dependency ref="dependencyRef"><dependency ref="transitiveDependencyRef"></dependency></Dependency>`, string(xmlBytes))
})
}

func TestDependency_UnmarshalXML(t *testing.T) {
t.Run("Empty", func(t *testing.T) {
dependency := Dependency{}
err := xml.Unmarshal([]byte(`<Dependency></Dependency>`), &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 ref="dependencyRef"></Dependency>`), &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 ref="dependencyRef"><dependency ref="transitiveDependencyRef"></dependency></Dependency>`), &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{
Expand Down
4 changes: 2 additions & 2 deletions example_test.go
Expand Up @@ -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",
},
},
{
Expand Down
Expand Up @@ -25,7 +25,8 @@
],
"dependencies": [
{
"ref": "library-a"
"ref": "library-a",
"dependsOn": []
},
{
"ref": "library-b",
Expand Down

0 comments on commit ea0d5b7

Please sign in to comment.