github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/formats/common/cyclonedxhelpers/licenses_test.go (about) 1 package cyclonedxhelpers 2 3 import ( 4 "testing" 5 6 "github.com/CycloneDX/cyclonedx-go" 7 "github.com/nextlinux/gosbom/gosbom/license" 8 "github.com/nextlinux/gosbom/gosbom/pkg" 9 "github.com/nextlinux/gosbom/internal" 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func Test_encodeLicense(t *testing.T) { 14 tests := []struct { 15 name string 16 input pkg.Package 17 expected *cyclonedx.Licenses 18 }{ 19 { 20 name: "no licenses", 21 input: pkg.Package{}, 22 }, 23 { 24 name: "no SPDX licenses", 25 input: pkg.Package{ 26 Licenses: pkg.NewLicenseSet( 27 pkg.NewLicense("RandomLicense"), 28 ), 29 }, 30 expected: &cyclonedx.Licenses{ 31 { 32 License: &cyclonedx.License{ 33 Name: "RandomLicense", 34 }, 35 }, 36 }, 37 }, 38 { 39 name: "single SPDX ID and Non SPDX ID", 40 input: pkg.Package{ 41 Licenses: pkg.NewLicenseSet( 42 pkg.NewLicense("mit"), 43 pkg.NewLicense("FOOBAR"), 44 ), 45 }, 46 expected: &cyclonedx.Licenses{ 47 { 48 License: &cyclonedx.License{ 49 ID: "MIT", 50 }, 51 }, 52 { 53 License: &cyclonedx.License{ 54 Name: "FOOBAR", 55 }, 56 }, 57 }, 58 }, 59 { 60 name: "with complex SPDX license expression", 61 input: pkg.Package{ 62 Licenses: pkg.NewLicenseSet( 63 pkg.NewLicense("MIT AND GPL-3.0-only"), 64 ), 65 }, 66 expected: &cyclonedx.Licenses{ 67 { 68 Expression: "MIT AND GPL-3.0-only", 69 }, 70 }, 71 }, 72 { 73 name: "with multiple complex SPDX license expression", 74 input: pkg.Package{ 75 Licenses: pkg.NewLicenseSet( 76 pkg.NewLicense("MIT AND GPL-3.0-only"), 77 pkg.NewLicense("MIT AND GPL-3.0-only WITH Classpath-exception-2.0"), 78 ), 79 }, 80 expected: &cyclonedx.Licenses{ 81 { 82 Expression: "(MIT AND GPL-3.0-only) AND (MIT AND GPL-3.0-only WITH Classpath-exception-2.0)", 83 }, 84 }, 85 }, 86 { 87 name: "with multiple URLs and expressions", 88 input: pkg.Package{ 89 Licenses: pkg.NewLicenseSet( 90 pkg.NewLicenseFromURLs("MIT", "https://opensource.org/licenses/MIT", "https://spdx.org/licenses/MIT.html"), 91 pkg.NewLicense("MIT AND GPL-3.0-only"), 92 pkg.NewLicenseFromURLs("FakeLicense", "htts://someurl.com"), 93 ), 94 }, 95 expected: &cyclonedx.Licenses{ 96 { 97 License: &cyclonedx.License{ 98 ID: "MIT", 99 URL: "https://opensource.org/licenses/MIT", 100 }, 101 }, 102 { 103 License: &cyclonedx.License{ 104 ID: "MIT", 105 URL: "https://spdx.org/licenses/MIT.html", 106 }, 107 }, 108 { 109 License: &cyclonedx.License{ 110 Name: "FakeLicense", 111 URL: "htts://someurl.com", 112 }, 113 }, 114 { 115 License: &cyclonedx.License{ 116 Name: "MIT AND GPL-3.0-only", 117 }, 118 }, 119 }, 120 }, 121 { 122 name: "with multiple values licenses are deduplicated", 123 input: pkg.Package{ 124 Licenses: pkg.NewLicenseSet( 125 pkg.NewLicense("Apache-2"), 126 pkg.NewLicense("Apache-2.0"), 127 ), 128 }, 129 expected: &cyclonedx.Licenses{ 130 { 131 License: &cyclonedx.License{ 132 ID: "Apache-2.0", 133 }, 134 }, 135 }, 136 }, 137 { 138 name: "with multiple URLs and single with no URLs", 139 input: pkg.Package{ 140 Licenses: pkg.NewLicenseSet( 141 pkg.NewLicense("MIT"), 142 pkg.NewLicenseFromURLs("MIT", "https://opensource.org/licenses/MIT", "https://spdx.org/licenses/MIT.html"), 143 pkg.NewLicense("MIT AND GPL-3.0-only"), 144 ), 145 }, 146 expected: &cyclonedx.Licenses{ 147 { 148 License: &cyclonedx.License{ 149 ID: "MIT", 150 URL: "https://opensource.org/licenses/MIT", 151 }, 152 }, 153 { 154 License: &cyclonedx.License{ 155 ID: "MIT", 156 URL: "https://spdx.org/licenses/MIT.html", 157 }, 158 }, 159 { 160 License: &cyclonedx.License{ 161 Name: "MIT AND GPL-3.0-only", 162 }, 163 }, 164 }, 165 }, 166 // TODO: do we drop the non SPDX ID license and do a single expression 167 // OR do we keep the non SPDX ID license and do multiple licenses where the complex 168 // expressions are set as the NAME field? 169 //{ 170 // name: "with multiple complex SPDX license expression and a non spdx id", 171 // input: pkg.Package{ 172 // Licenses: []pkg.License{ 173 // { 174 // SPDXExpression: "MIT AND GPL-3.0-only", 175 // }, 176 // { 177 // SPDXExpression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0", 178 // }, 179 // { 180 // Value: "FOOBAR", 181 // }, 182 // }, 183 // }, 184 // expected: &cyclonedx.Licenses{ 185 // { 186 // Expression: "(MIT AND GPL-3.0-only) AND (MIT AND GPL-3.0-only WITH Classpath-exception-2.0)", 187 // }, 188 // }, 189 //}, 190 } 191 for _, test := range tests { 192 t.Run(test.name, func(t *testing.T) { 193 assert.Equal(t, test.expected, encodeLicenses(test.input)) 194 }) 195 } 196 } 197 198 func TestDecodeLicenses(t *testing.T) { 199 tests := []struct { 200 name string 201 input *cyclonedx.Component 202 expected []pkg.License 203 }{ 204 { 205 name: "no licenses", 206 input: &cyclonedx.Component{}, 207 expected: []pkg.License{}, 208 }, 209 { 210 name: "no SPDX license ID or expression", 211 input: &cyclonedx.Component{ 212 Licenses: &cyclonedx.Licenses{ 213 { 214 License: &cyclonedx.License{ 215 Name: "RandomLicense", 216 }, 217 }, 218 }, 219 }, 220 expected: []pkg.License{ 221 { 222 Value: "RandomLicense", 223 // CycloneDX specification doesn't give a field for determining the license type 224 Type: license.Declared, 225 URLs: internal.NewStringSet(), 226 }, 227 }, 228 }, 229 { 230 name: "with SPDX license ID", 231 input: &cyclonedx.Component{ 232 Licenses: &cyclonedx.Licenses{ 233 { 234 License: &cyclonedx.License{ 235 ID: "MIT", 236 }, 237 }, 238 }, 239 }, 240 expected: []pkg.License{ 241 { 242 Value: "MIT", 243 SPDXExpression: "MIT", 244 Type: license.Declared, 245 URLs: internal.NewStringSet(), 246 }, 247 }, 248 }, 249 { 250 name: "with complex SPDX license expression", 251 input: &cyclonedx.Component{ 252 Licenses: &cyclonedx.Licenses{ 253 { 254 License: &cyclonedx.License{}, 255 Expression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0", 256 }, 257 }, 258 }, 259 expected: []pkg.License{ 260 { 261 Value: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0", 262 SPDXExpression: "MIT AND GPL-3.0-only WITH Classpath-exception-2.0", 263 Type: license.Declared, 264 URLs: internal.NewStringSet(), 265 }, 266 }, 267 }, 268 } 269 for _, test := range tests { 270 t.Run(test.name, func(t *testing.T) { 271 assert.Equal(t, test.expected, decodeLicenses(test.input)) 272 }) 273 } 274 }