mirror of
https://github.com/anchore/syft.git
synced 2026-11-03 07:56:36 +01:00
order locations by container layer order (#3858)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -59,7 +59,34 @@ func (s CoordinateSet) Paths() []string {
|
||||
return pathSlice
|
||||
}
|
||||
|
||||
func (s CoordinateSet) ToSlice() []Coordinates {
|
||||
func (s CoordinateSet) ToSlice(sorters ...func(a, b Coordinates) int) []Coordinates {
|
||||
coordinates := s.ToUnorderedSlice()
|
||||
|
||||
var sorted bool
|
||||
for _, sorter := range sorters {
|
||||
if sorter == nil {
|
||||
continue
|
||||
}
|
||||
sort.Slice(coordinates, func(i, j int) bool {
|
||||
return sorter(coordinates[i], coordinates[j]) < 0
|
||||
})
|
||||
sorted = true
|
||||
break
|
||||
}
|
||||
|
||||
if !sorted {
|
||||
sort.SliceStable(coordinates, func(i, j int) bool {
|
||||
if coordinates[i].FileSystemID == coordinates[j].FileSystemID {
|
||||
return coordinates[i].RealPath < coordinates[j].RealPath
|
||||
}
|
||||
return coordinates[i].FileSystemID < coordinates[j].FileSystemID
|
||||
})
|
||||
}
|
||||
|
||||
return coordinates
|
||||
}
|
||||
|
||||
func (s CoordinateSet) ToUnorderedSlice() []Coordinates {
|
||||
if s.set == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -69,12 +96,6 @@ func (s CoordinateSet) ToSlice() []Coordinates {
|
||||
coordinates[idx] = v
|
||||
idx++
|
||||
}
|
||||
sort.SliceStable(coordinates, func(i, j int) bool {
|
||||
if coordinates[i].RealPath == coordinates[j].RealPath {
|
||||
return coordinates[i].FileSystemID < coordinates[j].FileSystemID
|
||||
}
|
||||
return coordinates[i].RealPath < coordinates[j].RealPath
|
||||
})
|
||||
return coordinates
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/gohugoio/hashstructure"
|
||||
@@ -54,7 +55,28 @@ func (s LocationSet) Contains(l Location) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func (s LocationSet) ToSlice() []Location {
|
||||
func (s LocationSet) ToSlice(sorters ...func(a, b Location) int) []Location {
|
||||
locations := s.ToUnorderedSlice()
|
||||
|
||||
var sorted bool
|
||||
for _, sorter := range sorters {
|
||||
if sorter == nil {
|
||||
continue
|
||||
}
|
||||
slices.SortFunc(locations, sorter)
|
||||
sorted = true
|
||||
break
|
||||
}
|
||||
|
||||
if !sorted {
|
||||
// though no sorter was passed, we need to guarantee a stable ordering between calls
|
||||
sort.Sort(Locations(locations))
|
||||
}
|
||||
|
||||
return locations
|
||||
}
|
||||
|
||||
func (s LocationSet) ToUnorderedSlice() []Location {
|
||||
if s.set == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -67,7 +89,6 @@ func (s LocationSet) ToSlice() []Location {
|
||||
}
|
||||
idx++
|
||||
}
|
||||
sort.Sort(Locations(locations))
|
||||
return locations
|
||||
}
|
||||
|
||||
|
||||
@@ -89,8 +89,8 @@ func TestLocationSet_SortPaths(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
set := NewLocationSet(test.input...)
|
||||
assert.Equal(t, test.expected, set.ToSlice())
|
||||
actual := NewLocationSet(test.input...).ToSlice()
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+107
-20
@@ -1,6 +1,12 @@
|
||||
package file
|
||||
|
||||
import "github.com/anchore/syft/internal/evidence"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal/evidence"
|
||||
)
|
||||
|
||||
var locationSorterWithoutLayers = LocationSorter(nil)
|
||||
|
||||
type Locations []Location
|
||||
|
||||
@@ -9,27 +15,108 @@ func (l Locations) Len() int {
|
||||
}
|
||||
|
||||
func (l Locations) Less(i, j int) bool {
|
||||
liEvidence := l[i].Annotations[evidence.AnnotationKey]
|
||||
ljEvidence := l[j].Annotations[evidence.AnnotationKey]
|
||||
if liEvidence == ljEvidence {
|
||||
if l[i].RealPath == l[j].RealPath {
|
||||
if l[i].AccessPath == l[j].AccessPath {
|
||||
return l[i].FileSystemID < l[j].FileSystemID
|
||||
}
|
||||
return l[i].AccessPath < l[j].AccessPath
|
||||
}
|
||||
return l[i].RealPath < l[j].RealPath
|
||||
}
|
||||
if liEvidence == evidence.PrimaryAnnotation {
|
||||
return true
|
||||
}
|
||||
if ljEvidence == evidence.PrimaryAnnotation {
|
||||
return false
|
||||
}
|
||||
|
||||
return liEvidence > ljEvidence
|
||||
return locationSorterWithoutLayers(l[i], l[j]) < 0
|
||||
}
|
||||
|
||||
func (l Locations) Swap(i, j int) {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
|
||||
// LocationSorter creates a comparison function (slices.SortFunc) for Location objects based on layer order
|
||||
func LocationSorter(layers []string) func(a, b Location) int { //nolint:gocognit
|
||||
var layerOrderByDigest map[string]int
|
||||
if len(layers) > 0 {
|
||||
layerOrderByDigest = make(map[string]int)
|
||||
for i, digest := range layers {
|
||||
layerOrderByDigest[digest] = i
|
||||
}
|
||||
}
|
||||
|
||||
return func(a, b Location) int {
|
||||
// compare by evidence annotations first...
|
||||
aEvidence := a.Annotations[evidence.AnnotationKey]
|
||||
bEvidence := b.Annotations[evidence.AnnotationKey]
|
||||
|
||||
if aEvidence != bEvidence {
|
||||
if aEvidence == evidence.PrimaryAnnotation {
|
||||
return -1
|
||||
}
|
||||
if bEvidence == evidence.PrimaryAnnotation {
|
||||
return 1
|
||||
}
|
||||
|
||||
if aEvidence > bEvidence {
|
||||
return -1
|
||||
}
|
||||
if bEvidence > aEvidence {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// ...then by layer order
|
||||
if layerOrderByDigest != nil {
|
||||
// we're given layer order details
|
||||
aLayerIdx, aExists := layerOrderByDigest[a.FileSystemID]
|
||||
bLayerIdx, bExists := layerOrderByDigest[b.FileSystemID]
|
||||
|
||||
if aLayerIdx != bLayerIdx {
|
||||
if !aExists && !bExists {
|
||||
return strings.Compare(a.FileSystemID, b.FileSystemID)
|
||||
}
|
||||
if !aExists {
|
||||
return 1
|
||||
}
|
||||
if !bExists {
|
||||
return -1
|
||||
}
|
||||
|
||||
return aLayerIdx - bLayerIdx
|
||||
}
|
||||
} else if a.FileSystemID != b.FileSystemID {
|
||||
// no layer info given, legacy behavior is to sort lexicographically
|
||||
return strings.Compare(a.FileSystemID, b.FileSystemID)
|
||||
}
|
||||
|
||||
// ...then by paths
|
||||
if a.AccessPath != b.AccessPath {
|
||||
return strings.Compare(a.AccessPath, b.AccessPath)
|
||||
}
|
||||
|
||||
return strings.Compare(a.RealPath, b.RealPath)
|
||||
}
|
||||
}
|
||||
|
||||
// CoordinatesSorter creates a comparison function (slices.SortFunc) for Coordinate objects based on layer order
|
||||
func CoordinatesSorter(layers []string) func(a, b Coordinates) int {
|
||||
var layerOrderByDigest map[string]int
|
||||
if len(layers) > 0 {
|
||||
layerOrderByDigest = make(map[string]int)
|
||||
for i, digest := range layers {
|
||||
layerOrderByDigest[digest] = i
|
||||
}
|
||||
}
|
||||
|
||||
return func(a, b Coordinates) int {
|
||||
// ...then by layer order
|
||||
if layerOrderByDigest != nil {
|
||||
aLayerIdx, aExists := layerOrderByDigest[a.FileSystemID]
|
||||
bLayerIdx, bExists := layerOrderByDigest[b.FileSystemID]
|
||||
|
||||
if aLayerIdx != bLayerIdx {
|
||||
if !aExists && !bExists {
|
||||
return strings.Compare(a.FileSystemID, b.FileSystemID)
|
||||
}
|
||||
if !aExists {
|
||||
return 1
|
||||
}
|
||||
if !bExists {
|
||||
return -1
|
||||
}
|
||||
|
||||
return aLayerIdx - bLayerIdx
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Compare(a.RealPath, b.RealPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,557 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/anchore/syft/internal/evidence"
|
||||
)
|
||||
|
||||
func TestLocationAndCoordinatesSorters(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
layers []string
|
||||
locs []Location
|
||||
coords []Coordinates
|
||||
wantLocs []string
|
||||
wantCoords []string
|
||||
}{
|
||||
{
|
||||
name: "empty location slice",
|
||||
layers: []string{"fsid-1"},
|
||||
locs: []Location{},
|
||||
coords: []Coordinates{},
|
||||
wantLocs: []string{},
|
||||
wantCoords: []string{},
|
||||
},
|
||||
{
|
||||
name: "nil layer list",
|
||||
layers: nil,
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/a",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-2",
|
||||
},
|
||||
AccessPath: "/b",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-2",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/a (/a) @ fsid-1 map[]",
|
||||
"/b (/b) @ fsid-2 map[]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/a @ fsid-1",
|
||||
"/b @ fsid-2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sort by evidence type only",
|
||||
layers: []string{"fsid-1"},
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/a",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/b",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.SupportingAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/c",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/c",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/c",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/c (/c) @ fsid-1 map[evidence:primary]",
|
||||
"/b (/b) @ fsid-1 map[evidence:supporting]",
|
||||
"/a (/a) @ fsid-1 map[evidence:]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/a @ fsid-1",
|
||||
"/b @ fsid-1",
|
||||
"/c @ fsid-1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "same evidence type, sort by layer",
|
||||
layers: []string{"fsid-1", "fsid-2", "fsid-3"},
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-3",
|
||||
},
|
||||
AccessPath: "/a",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/b",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/c",
|
||||
FileSystemID: "fsid-2",
|
||||
},
|
||||
AccessPath: "/c",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-3",
|
||||
},
|
||||
{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/c",
|
||||
FileSystemID: "fsid-2",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/b (/b) @ fsid-1 map[evidence:primary]",
|
||||
"/c (/c) @ fsid-2 map[evidence:primary]",
|
||||
"/a (/a) @ fsid-3 map[evidence:primary]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/b @ fsid-1",
|
||||
"/c @ fsid-2",
|
||||
"/a @ fsid-3",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "same evidence and layer, sort by access path",
|
||||
layers: []string{"fsid-1"},
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/x",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/c",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/y",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/a",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/z",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/b",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/x",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/y",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/z",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/y (/a) @ fsid-1 map[evidence:primary]",
|
||||
"/z (/b) @ fsid-1 map[evidence:primary]",
|
||||
"/x (/c) @ fsid-1 map[evidence:primary]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/x @ fsid-1",
|
||||
"/y @ fsid-1",
|
||||
"/z @ fsid-1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "same evidence, layer, and access path - sort by real path",
|
||||
layers: []string{"fsid-1"},
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/c",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/same",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/same",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/same",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/c",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/a (/same) @ fsid-1 map[evidence:primary]",
|
||||
"/b (/same) @ fsid-1 map[evidence:primary]",
|
||||
"/c (/same) @ fsid-1 map[evidence:primary]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/a @ fsid-1",
|
||||
"/b @ fsid-1",
|
||||
"/c @ fsid-1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unknown layers",
|
||||
layers: []string{"fsid-1", "fsid-2"},
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "unknown-1",
|
||||
},
|
||||
AccessPath: "/a",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "unknown-2",
|
||||
},
|
||||
AccessPath: "/b",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "unknown-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "unknown-2",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/a (/a) @ unknown-1 map[]",
|
||||
"/b (/b) @ unknown-2 map[]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/a @ unknown-1",
|
||||
"/b @ unknown-2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed known and unknown layers",
|
||||
layers: []string{"fsid-1", "fsid-2"},
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/a",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "unknown",
|
||||
},
|
||||
AccessPath: "/b",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "unknown",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/a (/a) @ fsid-1 map[]",
|
||||
"/b (/b) @ unknown map[]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/a @ fsid-1",
|
||||
"/b @ unknown",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "evidence comparison when one has none",
|
||||
layers: []string{"fsid-1"},
|
||||
locs: []Location{
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/a",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
// No evidence.AnnotationKey
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LocationData: LocationData{
|
||||
Coordinates: Coordinates{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
AccessPath: "/b",
|
||||
},
|
||||
LocationMetadata: LocationMetadata{
|
||||
Annotations: map[string]string{
|
||||
evidence.AnnotationKey: evidence.PrimaryAnnotation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
coords: []Coordinates{
|
||||
{
|
||||
RealPath: "/a",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
{
|
||||
RealPath: "/b",
|
||||
FileSystemID: "fsid-1",
|
||||
},
|
||||
},
|
||||
wantLocs: []string{
|
||||
"/b (/b) @ fsid-1 map[evidence:primary]",
|
||||
"/a (/a) @ fsid-1 map[]",
|
||||
},
|
||||
wantCoords: []string{
|
||||
"/a @ fsid-1",
|
||||
"/b @ fsid-1",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run("Location", func(t *testing.T) {
|
||||
locs := make([]Location, len(tt.locs))
|
||||
copy(locs, tt.locs)
|
||||
|
||||
slices.SortFunc(locs, LocationSorter(tt.layers))
|
||||
|
||||
got := make([]string, len(locs))
|
||||
for i, loc := range locs {
|
||||
got[i] = fmt.Sprintf("%s (%s) @ %s %s",
|
||||
loc.RealPath,
|
||||
loc.AccessPath,
|
||||
loc.FileSystemID,
|
||||
loc.LocationMetadata.Annotations)
|
||||
}
|
||||
|
||||
if d := cmp.Diff(tt.wantLocs, got); d != "" {
|
||||
t.Errorf("LocationSorter() mismatch (-want +got):\n%s", d)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Coordinates", func(t *testing.T) {
|
||||
coords := make([]Coordinates, len(tt.coords))
|
||||
copy(coords, tt.coords)
|
||||
|
||||
slices.SortFunc(coords, CoordinatesSorter(tt.layers))
|
||||
|
||||
got := make([]string, len(coords))
|
||||
for i, coord := range coords {
|
||||
got[i] = fmt.Sprintf("%s @ %s",
|
||||
coord.RealPath,
|
||||
coord.FileSystemID)
|
||||
}
|
||||
|
||||
if d := cmp.Diff(tt.wantCoords, got); d != "" {
|
||||
t.Errorf("CoordinatesSorter() mismatch (-want +got):\n%s", d)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user