Skip to content

Commit

Permalink
Use values in relationship To/From fields (#2871)
Browse files Browse the repository at this point in the history
* use pkg values in relationship fields

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* add linter rule for using values in relationships

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* use new cmptest package for comparing relationships

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* create cmptest for common cmp.Diff options in test

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* condense matches for relationship ruleguard

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* remove relationship type from rules

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* restore build tag

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* suggest using values

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* nil check pkgs

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
  • Loading branch information
wagoodman authored May 14, 2024
1 parent 7ad7627 commit 048df17
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 134 deletions.
71 changes: 71 additions & 0 deletions internal/cmptest/common_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package cmptest

import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"

"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)

func DefaultCommonOptions() []cmp.Option {
return CommonOptions(nil, nil)
}

func CommonOptions(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.SortSlices(pkg.Less),
cmpopts.SortSlices(DefaultRelationshipComparer),
cmp.Comparer(
func(x, y file.LocationSet) bool {
xs := x.ToSlice()
ys := y.ToSlice()

if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !locationCmp(xe, ye) {
return false
}
}

return true
},
),
cmp.Comparer(
func(x, y pkg.LicenseSet) bool {
xs := x.ToSlice()
ys := y.ToSlice()

if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !licenseCmp(xe, ye) {
return false
}
}

return true
},
),
cmp.Comparer(
locationCmp,
),
cmp.Comparer(
licenseCmp,
),
}
}
37 changes: 37 additions & 0 deletions internal/cmptest/diff_reporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cmptest

import (
"fmt"
"strings"

"github.com/google/go-cmp/cmp"
)

// DiffReporter is a simple custom reporter that only records differences detected during comparison.
type DiffReporter struct {
path cmp.Path
diffs []string
}

func NewDiffReporter() DiffReporter {
return DiffReporter{}
}

func (r *DiffReporter) PushStep(ps cmp.PathStep) {
r.path = append(r.path, ps)
}

func (r *DiffReporter) Report(rs cmp.Result) {
if !rs.Equal() {
vx, vy := r.path.Last().Values()
r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy))
}
}

func (r *DiffReporter) PopStep() {
r.path = r.path[:len(r.path)-1]
}

func (r *DiffReporter) String() string {
return strings.Join(r.diffs, "\n")
}
29 changes: 29 additions & 0 deletions internal/cmptest/license.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cmptest

import (
"github.com/google/go-cmp/cmp"

"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)

type LicenseComparer func(x, y pkg.License) bool

func DefaultLicenseComparer(x, y pkg.License) bool {
return cmp.Equal(x, y, cmp.Comparer(DefaultLocationComparer), cmp.Comparer(
func(x, y file.LocationSet) bool {
xs := x.ToSlice()
ys := y.ToSlice()
if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !DefaultLocationComparer(xe, ye) {
return false
}
}
return true
},
))
}
13 changes: 13 additions & 0 deletions internal/cmptest/location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cmptest

import (
"github.com/google/go-cmp/cmp"

"github.com/anchore/syft/syft/file"
)

type LocationComparer func(x, y file.Location) bool

func DefaultLocationComparer(x, y file.Location) bool {
return cmp.Equal(x.Coordinates, y.Coordinates) && cmp.Equal(x.AccessPath, y.AccessPath)
}
26 changes: 26 additions & 0 deletions internal/cmptest/relationship.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cmptest

import (
"github.com/sanity-io/litter"

"github.com/anchore/syft/syft/artifact"
)

type RelationshipComparer func(x, y artifact.Relationship) bool

var relationshipStringer = litter.Options{
Compact: true,
StripPackageNames: false,
HidePrivateFields: true, // we want to ignore package IDs
HideZeroValues: true,
StrictGo: true,
//FieldExclusions: ... // these can be added for future values that need to be ignored
//FieldFilter: ...
}

func DefaultRelationshipComparer(x, y artifact.Relationship) bool {
// we just need a stable sort, the ordering does not need to be sensible
xStr := relationshipStringer.Sdump(x)
yStr := relationshipStringer.Sdump(y)
return xStr < yStr
}
14 changes: 12 additions & 2 deletions internal/relationship/by_file_ownership.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,19 @@ func byFileOwnershipOverlap(catalog *pkg.Collection) []artifact.Relationship {
parent := catalog.Package(parentID) // TODO: this is potentially expensive
child := catalog.Package(childID) // TODO: this is potentially expensive

if parent == nil {
log.Tracef("parent package not found: %v", parentID)
continue
}

if child == nil {
log.Tracef("child package not found: %v", childID)
continue
}

edges = append(edges, artifact.Relationship{
From: parent,
To: child,
From: *parent,
To: *child,
Type: artifact.OwnershipByFileOverlapRelationship,
Data: ownershipByFilesMetadata{
Files: fs,
Expand Down
9 changes: 5 additions & 4 deletions internal/relationship/by_file_ownership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package relationship
import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"

"github.com/anchore/syft/internal/cmptest"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
Expand Down Expand Up @@ -143,10 +145,9 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
assert.Len(t, relationships, len(expectedRelations))
for idx, expectedRelationship := range expectedRelations {
actualRelationship := relationships[idx]
assert.Equal(t, expectedRelationship.From.ID(), actualRelationship.From.ID())
assert.Equal(t, expectedRelationship.To.ID(), actualRelationship.To.ID())
assert.Equal(t, expectedRelationship.Type, actualRelationship.Type)
assert.Equal(t, expectedRelationship.Data, actualRelationship.Data)
if d := cmp.Diff(expectedRelationship, actualRelationship, cmptest.DefaultCommonOptions()...); d != "" {
t.Errorf("unexpected relationship (-want, +got): %s", d)
}
}
})
}
Expand Down
Loading

0 comments on commit 048df17

Please sign in to comment.