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  }