• 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

65.32
/spdx/v3/v3_0/spdx.go
1
package v3_0
2

3
import (
4
        "bytes"
5
        "encoding/json"
6
        "fmt"
7
        "io"
8
        "reflect"
9
        "time"
10

11
        "github.com/davecgh/go-spew/spew"
12
        "github.com/kzantow/go-ld"
13

14
        "github.com/spdx/tools-golang/spdx/v3/internal"
15
)
16

17
/*
18
SPDX 3 models and serialization code is generated from internal/generate/main.go
19
To regenerate all models, run: make generate
20
*/
21

22
const Version = "3.0.1" // TODO is there a way to ascertain this version from generated code programmatically?
23

24
type Document struct {
25
        SpdxDocument
26
        LDContext ld.Context
27
}
28

NEW
29
func (d *Document) UnmarshalJSON(data []byte) error {
×
NEW
30
        if d.LDContext == nil {
×
NEW
31
                d.LDContext = context()
×
NEW
32
        }
×
NEW
33
        err := d.FromJSON(bytes.NewReader(data))
×
NEW
34
        if err != nil {
×
NEW
35
                return err
×
NEW
36
        }
×
NEW
37
        return nil
×
38
}
39

NEW
40
func (d *Document) MarshalJSON() ([]byte, error) {
×
NEW
41
        if d.LDContext == nil {
×
NEW
42
                d.LDContext = context()
×
NEW
43
        }
×
NEW
44
        buf := bytes.Buffer{}
×
NEW
45
        err := d.Write(&buf)
×
NEW
46
        return buf.Bytes(), err
×
47
}
48

NEW
49
func (d *Document) Write(w io.Writer) error {
×
NEW
50
        return d.ToJSON(w)
×
NEW
51
}
×
52

53
func NewDocument(conformance ProfileIdentifierType, name string, createdBy AnyAgent, createdUsing AnyTool) *Document {
12✔
54
        if createdBy == nil {
12✔
NEW
55
                createdBy = &SoftwareAgent{
×
NEW
56
                        ID:                  "",
×
NEW
57
                        Description:         "",
×
NEW
58
                        Comment:             "",
×
NEW
59
                        Name:                "tools-golang",
×
NEW
60
                        Extensions:          nil,
×
NEW
61
                        CreationInfo:        nil,
×
NEW
62
                        ExternalIdentifiers: nil,
×
NEW
63
                        ExternalRefs:        nil,
×
NEW
64
                        Summary:             "",
×
NEW
65
                        VerifiedUsing:       nil,
×
NEW
66
                }
×
NEW
67
        }
×
68
        ci := &CreationInfo{
12✔
69
                SpecVersion:  Version,
12✔
70
                Created:      time.Now(),
12✔
71
                CreatedBy:    notNil(AgentList{createdBy}),
12✔
72
                CreatedUsing: notNil(ToolList{createdUsing}),
12✔
73
        }
12✔
74
        return &Document{
12✔
75
                SpdxDocument: SpdxDocument{
12✔
76
                        Name:                name,
12✔
77
                        CreationInfo:        ci,
12✔
78
                        ProfileConformances: conformanceFrom(conformance),
12✔
79
                },
12✔
80
                LDContext: context(),
12✔
81
        }
12✔
82
}
83

84
func conformanceFrom(conformance ProfileIdentifierType) []ProfileIdentifierType {
12✔
85
        out := []ProfileIdentifierType{ProfileIdentifierType_Core}
12✔
86
        switch conformance {
12✔
NEW
87
        case ProfileIdentifierType_Core:
×
88
        case ProfileIdentifierType_Software:
11✔
89
                out = append(out, conformance)
11✔
90
        case ProfileIdentifierType_Ai:
1✔
91
                out = append(out, ProfileIdentifierType_Software, conformance)
1✔
NEW
92
        case ProfileIdentifierType_Dataset:
×
NEW
93
                out = append(out, ProfileIdentifierType_Software, ProfileIdentifierType_Ai, conformance)
×
94
        }
95
        return out
12✔
96
}
97

98
func (d *Document) Validate(setCreationInfo bool) error {
4✔
99
        if setCreationInfo {
5✔
100
                // all Elements need to have creationInfo set...
1✔
101
                d.setCreationInfo(d.SpdxDocument.CreationInfo, &d.SpdxDocument)
1✔
102
        }
1✔
103
        return ld.ValidateGraph(d.SpdxDocument)
4✔
104
}
105

106
//func (d *Document) Append(e ...AnyElement) {
107
//        d.SpdxDocument.Elements = append(d.SpdxDocument.Elements, e...)
108
//        d.SpdxDocument.RootElements = append(d.SpdxDocument.RootElements, e...)
109
//}
110

111
// ToJSON first processes the document by:
112
//   - setting each Element's CreationInfo property to the SpdxDocument's CreationInfo if nil
113
//   - collecting all element references to the top-level Elements slice
114
//
115
// ... and after this initial processing, outputs the document as compact JSON LD,
116
// including accounting for empty IDs by outputting blank node spdxId values
117
func (d *Document) ToJSON(writer io.Writer) error {
6✔
118
        // all Elements need to have creationInfo set...
6✔
119
        d.setCreationInfo(d.SpdxDocument.CreationInfo, &d.SpdxDocument)
6✔
120

6✔
121
        // ensure the Elements
6✔
122
        d.ensureAllDocumentElements()
6✔
123

6✔
124
        if d.LDContext == nil {
6✔
NEW
125
                d.LDContext = context()
×
NEW
126
        }
×
127

128
        return internal.ToJSON("https://spdx.org/rdf/3.0.1/spdx-context.jsonld", d.LDContext, &d.SpdxDocument, writer)
6✔
129
}
130

131
func (d *Document) setCreationInfo(creationInfo AnyCreationInfo, doc *SpdxDocument) {
7✔
132
        if creationInfo == nil {
7✔
NEW
133
                return
×
NEW
134
        }
×
135
        creationInfoInterfaceType := reflect.TypeOf((*AnyCreationInfo)(nil)).Elem()
7✔
136
        ci := reflect.ValueOf(creationInfo)
7✔
137
        _ = ld.VisitObjectGraph(doc, func(path []any, value reflect.Value) error {
1,143✔
138
                t := value.Type()
1,136✔
139
                if t == creationInfoInterfaceType && value.IsNil() {
1,156✔
140
                        value.Set(ci)
20✔
141
                }
20✔
142
                return nil
1,136✔
143
        })
144
}
145

146
func (d *Document) FromJSON(reader io.Reader) error {
6✔
147
        graph, err := d.LDContext.FromJSON(reader)
6✔
148
        if err != nil {
6✔
NEW
149
                return err
×
NEW
150
        }
×
151
        for _, e := range graph {
35✔
152
                if doc, ok := e.(*SpdxDocument); ok {
35✔
153
                        d.SpdxDocument = *doc
6✔
154
                        return nil
6✔
155
                }
6✔
156
        }
NEW
157
        return fmt.Errorf("no SPDX document found")
×
158
}
159

160
func (d *Document) ensureAllDocumentElements() {
6✔
161
        all := map[reflect.Value]struct{}{}
6✔
162
        for _, e := range d.Elements {
16✔
163
                v := reflect.ValueOf(e)
10✔
164
                if v.Kind() != reflect.Pointer {
10✔
NEW
165
                        panic("non-pointer type in elements: %v" + spew.Sdump(v))
×
166
                }
167
                all[v] = struct{}{}
10✔
168
        }
169
        all[reflect.ValueOf(d.SpdxDocument)] = struct{}{}
6✔
170
        _ = ld.VisitObjectGraph(d.SpdxDocument, func(path []any, value reflect.Value) error {
962✔
171
                if value.Kind() == reflect.Pointer {
1,003✔
172
                        if _, ok := all[value]; ok {
57✔
173
                                return nil
10✔
174
                        }
10✔
175
                        if e, ok := value.Interface().(AnyElement); ok {
57✔
176
                                all[value] = struct{}{}
20✔
177
                                d.Elements = append(d.Elements, e)
20✔
178
                        }
20✔
179
                }
180
                return nil
946✔
181
        })
182
}
183

184
var _ interface {
185
        json.Marshaler
186
        json.Unmarshaler
187
} = (*Document)(nil)
188

189
func notNil[T any, ListType ~[]T](values ListType) ListType {
26✔
190
        var out ListType
26✔
191
        for _, v := range values {
52✔
192
                if isNil(v) {
28✔
193
                        continue
2✔
194
                }
195
                out = append(out, v)
24✔
196
        }
197
        return out
26✔
198
}
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