github.com/anchore/syft@v1.38.2/syft/file/location_set_test.go (about) 1 package file 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/internal/evidence" 11 "github.com/anchore/syft/syft/artifact" 12 ) 13 14 func TestLocationSet_SortPaths(t *testing.T) { 15 16 etcHostsLinkVar := Location{ 17 LocationData: LocationData{ 18 Coordinates: Coordinates{ 19 RealPath: "/etc/hosts", 20 FileSystemID: "a", 21 }, 22 AccessPath: "/var/etc/hosts", 23 }, 24 } 25 26 etcHostsLinkHome := Location{ 27 LocationData: LocationData{ 28 Coordinates: Coordinates{ 29 RealPath: "/etc/hosts", 30 FileSystemID: "a", 31 }, 32 AccessPath: "/home/wagoodman/hosts", 33 }, 34 } 35 36 binA := Location{ 37 LocationData: LocationData{ 38 Coordinates: Coordinates{ 39 RealPath: "/bin", 40 FileSystemID: "a", 41 }, 42 AccessPath: "/usr/bin", 43 }, 44 } 45 46 binB := Location{ 47 LocationData: LocationData{ 48 Coordinates: Coordinates{ 49 RealPath: "/bin", 50 FileSystemID: "b", 51 }, 52 AccessPath: "/usr/bin", 53 }, 54 } 55 56 tests := []struct { 57 name string 58 input []Location 59 expected []Location 60 }{ 61 { 62 name: "de-dup same location", 63 input: []Location{ 64 binA, binA, binA, 65 }, 66 expected: []Location{ 67 binA, 68 }, 69 }, 70 { 71 name: "dont de-dup different filesystem", 72 input: []Location{ 73 binB, binA, 74 }, 75 expected: []Location{ 76 binA, binB, 77 }, 78 }, 79 { 80 name: "dont de-dup different virtual paths", 81 input: []Location{ 82 etcHostsLinkVar, etcHostsLinkHome, 83 }, 84 expected: []Location{ 85 etcHostsLinkHome, etcHostsLinkVar, 86 }, 87 }, 88 } 89 90 for _, test := range tests { 91 t.Run(test.name, func(t *testing.T) { 92 actual := NewLocationSet(test.input...).ToSlice() 93 assert.Equal(t, test.expected, actual) 94 }) 95 } 96 } 97 98 func TestLocationSet_SortEvidence(t *testing.T) { 99 primaryEvidence := map[string]string{evidence.AnnotationKey: evidence.PrimaryAnnotation} 100 secondaryEvidence := map[string]string{evidence.AnnotationKey: evidence.SupportingAnnotation} 101 102 binPrimary := Location{ 103 LocationData: LocationData{ 104 Coordinates: Coordinates{ 105 RealPath: "/bin", 106 FileSystemID: "a", 107 }, 108 AccessPath: "/usr/bin", 109 }, 110 LocationMetadata: LocationMetadata{ 111 Annotations: primaryEvidence, 112 }, 113 } 114 115 binSecondary := Location{ 116 LocationData: LocationData{ 117 Coordinates: Coordinates{ 118 RealPath: "/bin", 119 FileSystemID: "a", 120 }, 121 AccessPath: "/usr/bin", 122 }, 123 LocationMetadata: LocationMetadata{ 124 Annotations: secondaryEvidence, 125 }, 126 } 127 128 binNoEvidence := Location{ 129 LocationData: LocationData{ 130 Coordinates: Coordinates{ 131 RealPath: "/bin", 132 FileSystemID: "a", 133 }, 134 AccessPath: "/usr/bin", 135 }, 136 } 137 138 etcHostsPrimary := Location{ 139 LocationData: LocationData{ 140 Coordinates: Coordinates{ 141 RealPath: "/etc/hosts", 142 FileSystemID: "a", 143 }, 144 AccessPath: "/var/etc/hosts", 145 }, 146 LocationMetadata: LocationMetadata{ 147 Annotations: primaryEvidence, 148 }, 149 } 150 151 etcHostsSecondary := Location{ 152 LocationData: LocationData{ 153 Coordinates: Coordinates{ 154 RealPath: "/etc/hosts", 155 FileSystemID: "a", 156 }, 157 AccessPath: "/var/etc/hosts", 158 }, 159 LocationMetadata: LocationMetadata{ 160 Annotations: secondaryEvidence, 161 }, 162 } 163 164 etcHostsNoEvidence := Location{ 165 LocationData: LocationData{ 166 Coordinates: Coordinates{ 167 RealPath: "/etc/hosts", 168 FileSystemID: "a", 169 }, 170 AccessPath: "/var/etc/hosts", 171 }, 172 } 173 174 tests := []struct { 175 name string 176 input []Location 177 expected []Location 178 }{ 179 { 180 name: "sort primary, secondary, tertiary, no evidence", 181 input: []Location{ 182 binNoEvidence, binPrimary, binSecondary, 183 }, 184 expected: []Location{ 185 binPrimary, binSecondary, binNoEvidence, 186 }, 187 }, 188 { 189 name: "sort by evidence, then path", 190 input: []Location{ 191 etcHostsNoEvidence, etcHostsSecondary, 192 binSecondary, binNoEvidence, 193 binPrimary, etcHostsPrimary, 194 }, 195 expected: []Location{ 196 binPrimary, etcHostsPrimary, binSecondary, etcHostsSecondary, binNoEvidence, etcHostsNoEvidence, 197 }, 198 }, 199 } 200 201 for _, test := range tests { 202 t.Run(test.name, func(t *testing.T) { 203 sort.Sort(Locations(test.input)) 204 assert.Equal(t, test.expected, test.input) 205 }) 206 } 207 } 208 209 func TestLocationSet_Hash(t *testing.T) { 210 etcAlink := Location{ 211 LocationData: LocationData{ 212 Coordinates: Coordinates{ 213 RealPath: "/etc/hosts", 214 FileSystemID: "a", 215 }, 216 AccessPath: "/var/etc/hosts", 217 }, 218 } 219 220 etcA := Location{ 221 LocationData: LocationData{ 222 Coordinates: Coordinates{ 223 RealPath: "/etc/hosts", 224 FileSystemID: "a", 225 }, 226 }, 227 } 228 229 etcB := Location{ 230 LocationData: LocationData{ 231 Coordinates: Coordinates{ 232 RealPath: "/etc/hosts", 233 FileSystemID: "b", 234 }, 235 }, 236 } 237 238 binA := Location{ 239 LocationData: LocationData{ 240 Coordinates: Coordinates{ 241 RealPath: "/bin", 242 FileSystemID: "a", 243 }, 244 AccessPath: "/usr/bin", 245 }, 246 } 247 248 binB := Location{ 249 LocationData: LocationData{ 250 Coordinates: Coordinates{ 251 RealPath: "/bin", 252 FileSystemID: "b", 253 }, 254 AccessPath: "/usr/bin", 255 }, 256 } 257 258 tests := []struct { 259 name string 260 setA LocationSet 261 setB LocationSet 262 want assert.ComparisonAssertionFunc 263 }{ 264 { 265 name: "empty sets have the same hash", 266 setA: NewLocationSet(), 267 setB: NewLocationSet(), 268 want: assert.Equal, 269 }, 270 { 271 name: "sets with same elements accessed through different paths have the same hash", 272 setA: NewLocationSet(binA, etcA), 273 setB: NewLocationSet(etcAlink, binA), 274 want: assert.Equal, 275 }, 276 { 277 name: "sets with same elements have the same hash", 278 setA: NewLocationSet(binA, etcA), 279 setB: NewLocationSet(etcA, binA), 280 want: assert.Equal, 281 }, 282 { 283 name: "sets with different element counts have different hashes", 284 setA: NewLocationSet(binA, etcA), 285 setB: NewLocationSet(binA), 286 want: assert.NotEqual, 287 }, 288 { 289 name: "sets with same path but different FS IDs have the same hash", 290 setA: NewLocationSet(binA), 291 setB: NewLocationSet(binB), 292 want: assert.Equal, 293 }, 294 { 295 name: "sets with same paths but different FS IDs have the same hash", 296 setA: NewLocationSet(etcA, binA), 297 setB: NewLocationSet(binB, etcB), 298 want: assert.Equal, 299 }, 300 } 301 for _, tt := range tests { 302 t.Run(tt.name, func(t *testing.T) { 303 gotA, err := artifact.IDByHash(tt.setA) 304 require.NoError(t, err) 305 gotB, err := artifact.IDByHash(tt.setB) 306 require.NoError(t, err) 307 tt.want(t, gotA, gotB) 308 }) 309 } 310 }