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