github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/license_test.go (about) 1 package pkg 2 3 import ( 4 "sort" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 10 "github.com/anchore/syft/syft/artifact" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/license" 13 ) 14 15 func Test_Hash(t *testing.T) { 16 17 loc1 := file.NewLocation("place!") 18 loc1.FileSystemID = "fs1" 19 loc2 := file.NewLocation("place!") 20 loc2.FileSystemID = "fs2" // important! there is a different file system ID 21 22 lic1 := NewLicenseFromFields("MIT", "foo", &loc1) 23 lic2 := NewLicenseFromFields("MIT", "bar", &loc2) 24 25 hash1, err := artifact.IDByHash(lic1) 26 require.NoError(t, err) 27 28 hash2, err := artifact.IDByHash(lic2) 29 require.NoError(t, err) 30 31 assert.Equal(t, hash1, hash2) 32 } 33 34 func Test_Sort(t *testing.T) { 35 tests := []struct { 36 name string 37 licenses Licenses 38 expected Licenses 39 }{ 40 { 41 name: "empty", 42 licenses: []License{}, 43 expected: []License{}, 44 }, 45 { 46 name: "single", 47 licenses: []License{ 48 NewLicenseFromLocations("MIT", file.NewLocation("place!")), 49 }, 50 expected: []License{ 51 NewLicenseFromLocations("MIT", file.NewLocation("place!")), 52 }, 53 }, 54 { 55 name: "multiple", 56 licenses: []License{ 57 NewLicenseFromLocations("MIT", file.NewLocation("place!")), 58 NewLicenseFromURLs("MIT", "https://github.com/anchore/syft/blob/main/LICENSE"), 59 NewLicenseFromLocations("Apache", file.NewLocation("area!")), 60 NewLicenseFromLocations("gpl2+", file.NewLocation("area!")), 61 }, 62 expected: Licenses{ 63 NewLicenseFromLocations("Apache", file.NewLocation("area!")), 64 NewLicenseFromURLs("MIT", "https://github.com/anchore/syft/blob/main/LICENSE"), 65 NewLicenseFromLocations("MIT", file.NewLocation("place!")), 66 NewLicenseFromLocations("gpl2+", file.NewLocation("area!")), 67 }, 68 }, 69 { 70 name: "multiple with location variants", 71 licenses: []License{ 72 NewLicenseFromLocations("MIT", file.NewLocation("place!")), 73 NewLicenseFromLocations("MIT", file.NewLocation("park!")), 74 NewLicense("MIT"), 75 NewLicense("AAL"), 76 NewLicense("Adobe-2006"), 77 NewLicenseFromLocations("Apache", file.NewLocation("area!")), 78 }, 79 expected: Licenses{ 80 NewLicense("AAL"), 81 NewLicense("Adobe-2006"), 82 NewLicenseFromLocations("Apache", file.NewLocation("area!")), 83 NewLicense("MIT"), 84 NewLicenseFromLocations("MIT", file.NewLocation("park!")), 85 NewLicenseFromLocations("MIT", file.NewLocation("place!")), 86 }, 87 }, 88 } 89 90 for _, test := range tests { 91 t.Run(test.name, func(t *testing.T) { 92 sort.Sort(test.licenses) 93 assert.Equal(t, test.expected, test.licenses) 94 }) 95 96 } 97 } 98 99 func TestLicense_Merge(t *testing.T) { 100 locA := file.NewLocation("a") 101 locB := file.NewLocation("b") 102 103 tests := []struct { 104 name string 105 subject License 106 other License 107 want License 108 wantErr require.ErrorAssertionFunc 109 }{ 110 { 111 name: "valid merge", 112 subject: License{ 113 Value: "MIT", 114 SPDXExpression: "MIT", 115 Type: license.Declared, 116 URLs: []string{ 117 "b", "a", 118 }, 119 Locations: file.NewLocationSet(locA), 120 }, 121 other: License{ 122 Value: "MIT", 123 SPDXExpression: "MIT", 124 Type: license.Declared, 125 URLs: []string{ 126 "c", "d", 127 }, 128 Locations: file.NewLocationSet(locB), 129 }, 130 want: License{ 131 Value: "MIT", 132 SPDXExpression: "MIT", 133 Type: license.Declared, 134 URLs: []string{ 135 "a", "b", "c", "d", 136 }, 137 Locations: file.NewLocationSet(locA, locB), 138 }, 139 }, 140 { 141 name: "mismatched value", 142 subject: License{ 143 Value: "DIFFERENT!!", 144 SPDXExpression: "MIT", 145 Type: license.Declared, 146 URLs: []string{ 147 "b", "a", 148 }, 149 Locations: file.NewLocationSet(locA), 150 }, 151 other: License{ 152 Value: "MIT", 153 SPDXExpression: "MIT", 154 Type: license.Declared, 155 URLs: []string{ 156 "c", "d", 157 }, 158 Locations: file.NewLocationSet(locB), 159 }, 160 wantErr: require.Error, 161 }, 162 { 163 name: "mismatched spdx expression", 164 subject: License{ 165 Value: "MIT", 166 SPDXExpression: "DIFFERENT!!", 167 Type: license.Declared, 168 URLs: []string{ 169 "b", "a", 170 }, 171 Locations: file.NewLocationSet(locA), 172 }, 173 other: License{ 174 Value: "MIT", 175 SPDXExpression: "MIT", 176 Type: license.Declared, 177 URLs: []string{ 178 "c", "d", 179 }, 180 Locations: file.NewLocationSet(locB), 181 }, 182 wantErr: require.Error, 183 }, 184 { 185 name: "mismatched type", 186 subject: License{ 187 Value: "MIT", 188 SPDXExpression: "MIT", 189 Type: license.Concluded, 190 URLs: []string{ 191 "b", "a", 192 }, 193 Locations: file.NewLocationSet(locA), 194 }, 195 other: License{ 196 Value: "MIT", 197 SPDXExpression: "MIT", 198 Type: license.Declared, 199 URLs: []string{ 200 "c", "d", 201 }, 202 Locations: file.NewLocationSet(locB), 203 }, 204 wantErr: require.Error, 205 }, 206 } 207 for _, tt := range tests { 208 t.Run(tt.name, func(t *testing.T) { 209 if tt.wantErr == nil { 210 tt.wantErr = require.NoError 211 } 212 213 subjectLocationLen := len(tt.subject.Locations.ToSlice()) 214 subjectURLLen := len(tt.subject.URLs) 215 216 got, err := tt.subject.Merge(tt.other) 217 tt.wantErr(t, err) 218 if err != nil { 219 return 220 } 221 require.NotNilf(t, got, "expected a non-nil license") 222 assert.Equal(t, tt.want, *got) 223 // prove we don't modify the subject 224 assert.Equal(t, subjectLocationLen, len(tt.subject.Locations.ToSlice())) 225 assert.Equal(t, subjectURLLen, len(tt.subject.URLs)) 226 }) 227 } 228 }