github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/formats/common/spdxhelpers/license_test.go (about) 1 package spdxhelpers 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/spdx/tools-golang/spdx" 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/anchore/syft/internal/spdxlicense" 12 "github.com/anchore/syft/syft/pkg" 13 "github.com/anchore/syft/syft/sbom" 14 ) 15 16 func Test_License(t *testing.T) { 17 type expected struct { 18 concluded string 19 declared string 20 } 21 tests := []struct { 22 name string 23 input pkg.Package 24 expected expected 25 }{ 26 { 27 name: "no licenses", 28 input: pkg.Package{}, 29 expected: expected{ 30 concluded: "NOASSERTION", 31 declared: "NOASSERTION", 32 }, 33 }, 34 { 35 name: "no SPDX licenses", 36 input: pkg.Package{ 37 Licenses: pkg.NewLicenseSet(pkg.NewLicense("made-up")), 38 }, 39 expected: expected{ 40 concluded: "NOASSERTION", 41 declared: "LicenseRef-made-up", 42 }, 43 }, 44 { 45 name: "with SPDX license", 46 input: pkg.Package{ 47 Licenses: pkg.NewLicenseSet(pkg.NewLicense("MIT")), 48 }, 49 expected: struct { 50 concluded string 51 declared string 52 }{ 53 concluded: "NOASSERTION", 54 declared: "MIT", 55 }, 56 }, 57 { 58 name: "with SPDX license expression", 59 input: pkg.Package{ 60 Licenses: pkg.NewLicenseSet( 61 pkg.NewLicense("MIT"), 62 pkg.NewLicense("GPL-3.0-only"), 63 ), 64 }, 65 expected: expected{ 66 concluded: "NOASSERTION", 67 // because we sort licenses alphabetically GPL ends up at the start 68 declared: "GPL-3.0-only AND MIT", 69 }, 70 }, 71 { 72 name: "includes valid LicenseRef-", 73 input: pkg.Package{ 74 Licenses: pkg.NewLicenseSet( 75 pkg.NewLicense("one thing first"), 76 pkg.NewLicense("two things/#$^second"), 77 pkg.NewLicense("MIT"), 78 ), 79 }, 80 expected: expected{ 81 concluded: "NOASSERTION", 82 // because we separate licenses between valid SPDX and non valid, valid ID always end at the front 83 declared: "MIT AND LicenseRef-one-thing-first AND LicenseRef-two-things----second", 84 }, 85 }, 86 { 87 name: "join parentheses correctly", 88 input: pkg.Package{ 89 Licenses: pkg.NewLicenseSet( 90 pkg.NewLicense("one thing first"), 91 pkg.NewLicense("MIT AND GPL-3.0-only"), 92 pkg.NewLicense("MIT OR APACHE-2.0"), 93 ), 94 }, 95 expected: expected{ 96 concluded: "NOASSERTION", 97 // because we separate licenses between valid SPDX and non valid, valid ID always end at the front 98 declared: "(MIT AND GPL-3.0-only) AND (MIT OR APACHE-2.0) AND LicenseRef-one-thing-first", 99 }, 100 }, 101 } 102 for _, test := range tests { 103 t.Run(test.name, func(t *testing.T) { 104 c, d := License(test.input) 105 assert.Equal(t, test.expected.concluded, c) 106 assert.Equal(t, test.expected.declared, d) 107 }) 108 } 109 } 110 111 func Test_otherLicenses(t *testing.T) { 112 pkg1 := pkg.Package{ 113 Name: "first-pkg", 114 Version: "1.1", 115 Licenses: pkg.NewLicenseSet( 116 pkg.NewLicense("MIT"), 117 ), 118 } 119 pkg2 := pkg.Package{ 120 Name: "second-pkg", 121 Version: "2.2", 122 Licenses: pkg.NewLicenseSet( 123 pkg.NewLicense("non spdx license"), 124 ), 125 } 126 bigText := ` 127 Apache License 128 Version 2.0, January 2004` 129 pkg3 := pkg.Package{ 130 Name: "third-pkg", 131 Version: "3.3", 132 Licenses: pkg.NewLicenseSet( 133 pkg.NewLicense(bigText), 134 ), 135 } 136 137 tests := []struct { 138 name string 139 packages []pkg.Package 140 expected []*spdx.OtherLicense 141 }{ 142 { 143 name: "no other licenses when all valid spdx expressions", 144 packages: []pkg.Package{pkg1}, 145 expected: nil, 146 }, 147 { 148 name: "other licenses includes original text", 149 packages: []pkg.Package{pkg2}, 150 expected: []*spdx.OtherLicense{ 151 { 152 LicenseIdentifier: "LicenseRef-non-spdx-license", 153 ExtractedText: "non spdx license", 154 }, 155 }, 156 }, 157 { 158 name: "big licenses get hashed", 159 packages: []pkg.Package{pkg3}, 160 expected: []*spdx.OtherLicense{ 161 { 162 LicenseIdentifier: "LicenseRef-e9a1e42833d3e456f147052f4d312101bd171a0798893169fe596ca6b55c049e", 163 ExtractedText: bigText, 164 }, 165 }, 166 }, 167 } 168 169 for _, test := range tests { 170 t.Run(test.name, func(t *testing.T) { 171 s := sbom.SBOM{ 172 Artifacts: sbom.Artifacts{ 173 Packages: pkg.NewCollection(test.packages...), 174 }, 175 } 176 got := ToFormatModel(s) 177 require.Equal(t, test.expected, got.OtherLicenses) 178 }) 179 } 180 } 181 182 func Test_joinLicenses(t *testing.T) { 183 tests := []struct { 184 name string 185 args []string 186 want string 187 }{ 188 { 189 name: "multiple licenses", 190 args: []string{"MIT", "GPL-3.0-only"}, 191 want: "MIT AND GPL-3.0-only", 192 }, 193 { 194 name: "multiple licenses with complex expressions", 195 args: []string{"MIT AND Apache", "GPL-3.0-only"}, 196 want: "(MIT AND Apache) AND GPL-3.0-only", 197 }, 198 } 199 for _, tt := range tests { 200 t.Run(tt.name, func(t *testing.T) { 201 assert.Equalf(t, tt.want, joinLicenses(toSpdxLicenses(tt.args)), "joinLicenses(%v)", tt.args) 202 }) 203 } 204 } 205 206 func toSpdxLicenses(ids []string) (licenses []spdxLicense) { 207 for _, l := range ids { 208 license := spdxLicense{id: l} 209 if strings.HasPrefix(l, spdxlicense.LicenseRefPrefix) { 210 license.value = l 211 } 212 licenses = append(licenses, license) 213 } 214 return licenses 215 }