• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

spdx / tools-golang / 18390436414

09 Oct 2025 10:09PM UTC coverage: 87.135% (-8.3%) from 95.483%
18390436414

Pull #247

github

kzantow
chore: cleanup test logging, misc fixes

Signed-off-by: Keith Zantow <kzantow@gmail.com>
Pull Request #247: feat: SPDX 3

1476 of 1606 new or added lines in 8 files covered. (91.91%)

11 existing lines in 1 file now uncovered.

9042 of 10377 relevant lines covered (87.14%)

22.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.53
/spdx/v2/v2_2/document.go
1
// Package spdx contains the struct definition for an SPDX Document
2
// and its constituent parts.
3
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
4
package v2_2
5

6
import (
7
        "encoding/json"
8
        "fmt"
9

10
        "github.com/spdx/tools-golang/spdx/v2/common"
11
        "github.com/spdx/tools-golang/spdx/v2/v2_1"
12
)
13

14
const Version = "SPDX-2.2"
15
const DataLicense = "CC0-1.0"
16

17
// ExternalDocumentRef is a reference to an external SPDX document
18
// as defined in section 6.6 for version 2.2 of the spec.
19
type ExternalDocumentRef struct {
20
        // DocumentRefID is the ID string defined in the start of the
21
        // reference. It should _not_ contain the "DocumentRef-" part
22
        // of the mandatory ID string.
23
        DocumentRefID string `json:"externalDocumentId"`
24

25
        // URI is the URI defined for the external document
26
        URI string `json:"spdxDocument"`
27

28
        // Checksum is the actual hash data
29
        Checksum common.Checksum `json:"checksum"`
30
}
31

32
// Document is an SPDX Document for version 2.2 of the spec.
33
// See https://spdx.github.io/spdx-spec/v2-draft/ (DRAFT)
34
type Document struct {
35
        // 6.1: SPDX Version; should be in the format "SPDX-2.2"
36
        // Cardinality: mandatory, one
37
        SPDXVersion string `json:"spdxVersion"`
38

39
        // 6.2: Data License; should be "CC0-1.0"
40
        // Cardinality: mandatory, one
41
        DataLicense string `json:"dataLicense"`
42

43
        // 6.3: SPDX Identifier; should be "DOCUMENT" to represent
44
        //      mandatory identifier of SPDXRef-DOCUMENT
45
        // Cardinality: mandatory, one
46
        SPDXIdentifier common.ElementID `json:"SPDXID"`
47

48
        // 6.4: Document Name
49
        // Cardinality: mandatory, one
50
        DocumentName string `json:"name"`
51

52
        // 6.5: Document Namespace
53
        // Cardinality: mandatory, one
54
        DocumentNamespace string `json:"documentNamespace"`
55

56
        // 6.6: External Document References
57
        // Cardinality: optional, one or many
58
        ExternalDocumentReferences []ExternalDocumentRef `json:"externalDocumentRefs,omitempty"`
59

60
        // 6.11: Document Comment
61
        // Cardinality: optional, one
62
        DocumentComment string `json:"comment,omitempty"`
63

64
        CreationInfo  *CreationInfo   `json:"creationInfo"`
65
        Packages      []*Package      `json:"packages,omitempty"`
66
        Files         []*File         `json:"files,omitempty"`
67
        OtherLicenses []*OtherLicense `json:"hasExtractedLicensingInfos,omitempty"`
68
        Relationships []*Relationship `json:"relationships,omitempty"`
69
        Annotations   []*Annotation   `json:"annotations,omitempty"`
70
        Snippets      []Snippet       `json:"snippets,omitempty"`
71

72
        // DEPRECATED in version 2.0 of spec
73
        Reviews []*Review `json:"-"`
74
}
75

76
func From_v2_1(_ v2_1.Document, d *Document) {
1✔
77
        d.SPDXVersion = Version
1✔
78
}
1✔
79

NEW
80
func To_v2_1(_ Document, d *v2_1.Document) {
×
NEW
81
        d.SPDXVersion = v2_1.Version
×
NEW
82
}
×
83

84
func (d *Document) UnmarshalJSON(b []byte) error {
8✔
85
        type doc Document
8✔
86
        type extras struct {
8✔
87
                DocumentDescribes []common.DocElementID `json:"documentDescribes"`
8✔
88
        }
8✔
89

8✔
90
        var d2 doc
8✔
91
        if err := json.Unmarshal(b, &d2); err != nil {
8✔
92
                return err
×
93
        }
×
94

95
        var e extras
8✔
96
        if err := json.Unmarshal(b, &e); err != nil {
8✔
97
                return err
×
98
        }
×
99

100
        *d = Document(d2)
8✔
101

8✔
102
        relationshipExists := map[string]bool{}
8✔
103
        serializeRel := func(r *Relationship) string {
78✔
104
                refA := r.RefA
70✔
105
                refB := r.RefB
70✔
106
                rel := r.Relationship
70✔
107

70✔
108
                // we need to serialize the opposite for CONTAINED_BY and DESCRIBED_BY
70✔
109
                // so that it will match when we try to de-duplicate during deserialization.
70✔
110
                switch r.Relationship {
70✔
111
                case common.TypeRelationshipContainedBy:
1✔
112
                        rel = common.TypeRelationshipContains
1✔
113
                        refA = r.RefB
1✔
114
                        refB = r.RefA
1✔
115
                case common.TypeRelationshipDescribeBy:
×
116
                        rel = common.TypeRelationshipDescribe
×
117
                        refA = r.RefB
×
118
                        refB = r.RefA
×
119
                }
120
                return fmt.Sprintf("%v-%v->%v", common.RenderDocElementID(refA), rel, common.RenderDocElementID(refB))
70✔
121
        }
122

123
        // remove null relationships
124
        for i := 0; i < len(d.Relationships); i++ {
55✔
125
                if d.Relationships[i] == nil {
50✔
126
                        d.Relationships = append(d.Relationships[0:i], d.Relationships[i+1:]...)
3✔
127
                        i--
3✔
128
                }
3✔
129
        }
130

131
        // index current list of relationships to ensure no duplication
132
        for _, r := range d.Relationships {
52✔
133
                relationshipExists[serializeRel(r)] = true
44✔
134
        }
44✔
135

136
        // build relationships for documentDescribes field
137
        for _, id := range e.DocumentDescribes {
15✔
138
                r := &Relationship{
7✔
139
                        RefA: common.DocElementID{
7✔
140
                                ElementRefID: d.SPDXIdentifier,
7✔
141
                        },
7✔
142
                        RefB:         id,
7✔
143
                        Relationship: common.TypeRelationshipDescribe,
7✔
144
                }
7✔
145

7✔
146
                if !relationshipExists[serializeRel(r)] {
10✔
147
                        d.Relationships = append(d.Relationships, r)
3✔
148
                        relationshipExists[serializeRel(r)] = true
3✔
149
                }
3✔
150
        }
151

152
        // build relationships for package hasFiles field
153
        for _, p := range d.Packages {
37✔
154
                for _, f := range p.hasFiles {
39✔
155
                        r := &Relationship{
10✔
156
                                RefA: common.DocElementID{
10✔
157
                                        ElementRefID: p.PackageSPDXIdentifier,
10✔
158
                                },
10✔
159
                                RefB:         f,
10✔
160
                                Relationship: common.TypeRelationshipContains,
10✔
161
                        }
10✔
162
                        if !relationshipExists[serializeRel(r)] {
16✔
163
                                d.Relationships = append(d.Relationships, r)
6✔
164
                                relationshipExists[serializeRel(r)] = true
6✔
165
                        }
6✔
166
                }
167

168
                p.hasFiles = nil
29✔
169
        }
170

171
        return nil
8✔
172
}
173

174
var _ json.Unmarshaler = (*Document)(nil)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc