package cmptest import ( "strings" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/anchore/syft/internal/evidence" "github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/pkg" ) func DefaultOptions() []cmp.Option { return BuildOptions(nil, nil) } func DefaultIgnoreLocationLayerOptions() []cmp.Option { return BuildOptions(LicenseComparerWithoutLocationLayer, LocationComparerWithoutLayer) } func BuildOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []cmp.Option { if licenseCmp == nil { licenseCmp = DefaultLicenseComparer } if locationCmp == nil { locationCmp = DefaultLocationComparer } return []cmp.Option{ cmpopts.IgnoreFields(pkg.Package{}, "id"), // note: ID is not deterministic for test purposes cmpopts.IgnoreFields(pkg.Package{}, "FoundBy"), // not necessary in most tests cmpopts.SortSlices(pkg.Less), cmpopts.SortSlices(DefaultRelationshipComparer), cmp.Comparer(buildSetComparer[file.Location, file.LocationSet](locationCmp, locationSorter)), cmp.Comparer(buildSetComparer[pkg.License, pkg.LicenseSet](licenseCmp)), cmp.Comparer(locationCmp), cmp.Comparer(licenseCmp), } } // LocationSorter always sorts by evidence annotations first, then by access path, then by real path. // This intentionally does not consider layer details since some test fixtures have no layer information // on the left side of the comparison (expected) and does on the right side (actual). func locationSorter(a, b file.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 paths if a.AccessPath != b.AccessPath { return strings.Compare(a.AccessPath, b.AccessPath) } return strings.Compare(a.RealPath, b.RealPath) }