github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/internal/fileresolver/excluding_file_test.go (about)

     1  package fileresolver
     2  
     3  import (
     4  	"io"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  
    10  	"github.com/anchore/syft/syft/file"
    11  )
    12  
    13  func TestExcludingResolver(t *testing.T) {
    14  
    15  	tests := []struct {
    16  		name      string
    17  		locations []string
    18  		excludeFn excludeFn
    19  		expected  []string
    20  	}{
    21  		{
    22  			name:      "keeps locations",
    23  			locations: []string{"a", "b", "c"},
    24  			excludeFn: func(s string) bool {
    25  				return false
    26  			},
    27  			expected: []string{"a", "b", "c"},
    28  		},
    29  		{
    30  			name:      "removes locations",
    31  			locations: []string{"d", "e", "f"},
    32  			excludeFn: func(s string) bool {
    33  				return true
    34  			},
    35  			expected: []string{},
    36  		},
    37  		{
    38  			name:      "removes first match",
    39  			locations: []string{"g", "h", "i"},
    40  			excludeFn: func(s string) bool {
    41  				return s == "g"
    42  			},
    43  			expected: []string{"h", "i"},
    44  		},
    45  		{
    46  			name:      "removes last match",
    47  			locations: []string{"j", "k", "l"},
    48  			excludeFn: func(s string) bool {
    49  				return s == "l"
    50  			},
    51  			expected: []string{"j", "k"},
    52  		},
    53  	}
    54  	for _, test := range tests {
    55  		t.Run(test.name, func(t *testing.T) {
    56  			resolver := &mockResolver{
    57  				locations: test.locations,
    58  			}
    59  			er := NewExcludingDecorator(resolver, test.excludeFn)
    60  
    61  			locations, _ := er.FilesByPath()
    62  			assert.ElementsMatch(t, locationPaths(locations), test.expected)
    63  
    64  			locations, _ = er.FilesByGlob()
    65  			assert.ElementsMatch(t, locationPaths(locations), test.expected)
    66  
    67  			locations, _ = er.FilesByMIMEType()
    68  			assert.ElementsMatch(t, locationPaths(locations), test.expected)
    69  
    70  			locations = []file.Location{}
    71  
    72  			channel := er.AllLocations()
    73  			for location := range channel {
    74  				locations = append(locations, location)
    75  			}
    76  			assert.ElementsMatch(t, locationPaths(locations), test.expected)
    77  
    78  			diff := difference(test.locations, test.expected)
    79  
    80  			for _, path := range diff {
    81  				assert.False(t, er.HasPath(path))
    82  				c, err := er.FileContentsByLocation(file.NewLocation(path))
    83  				assert.Nil(t, c)
    84  				assert.Error(t, err)
    85  				m, err := er.FileMetadataByLocation(file.NewLocation(path))
    86  				assert.Empty(t, m.LinkDestination)
    87  				assert.Error(t, err)
    88  				l := er.RelativeFileByPath(file.NewLocation(""), path)
    89  				assert.Nil(t, l)
    90  			}
    91  
    92  			for _, path := range test.expected {
    93  				assert.True(t, er.HasPath(path))
    94  				c, err := er.FileContentsByLocation(file.NewLocation(path))
    95  				assert.NotNil(t, c)
    96  				assert.Nil(t, err)
    97  				m, err := er.FileMetadataByLocation(file.NewLocation(path))
    98  				assert.NotEmpty(t, m.LinkDestination)
    99  				assert.Nil(t, err)
   100  				l := er.RelativeFileByPath(file.NewLocation(""), path)
   101  				assert.NotNil(t, l)
   102  			}
   103  		})
   104  	}
   105  }
   106  
   107  // difference returns the elements in `a` that aren't in `b`.
   108  func difference(a, b []string) []string {
   109  	mb := make(map[string]struct{}, len(b))
   110  	for _, x := range b {
   111  		mb[x] = struct{}{}
   112  	}
   113  	var diff []string
   114  	for _, x := range a {
   115  		if _, found := mb[x]; !found {
   116  			diff = append(diff, x)
   117  		}
   118  	}
   119  	return diff
   120  }
   121  
   122  func locationPaths(locations []file.Location) []string {
   123  	paths := []string{}
   124  	for _, l := range locations {
   125  		paths = append(paths, l.RealPath)
   126  	}
   127  	return paths
   128  }
   129  
   130  type mockResolver struct {
   131  	locations []string
   132  }
   133  
   134  func (r *mockResolver) getLocations() ([]file.Location, error) {
   135  	out := []file.Location{}
   136  	for _, path := range r.locations {
   137  		out = append(out, file.NewLocation(path))
   138  	}
   139  	return out, nil
   140  }
   141  
   142  func (r *mockResolver) FileContentsByLocation(_ file.Location) (io.ReadCloser, error) {
   143  	return io.NopCloser(strings.NewReader("Hello, world!")), nil
   144  }
   145  
   146  func (r *mockResolver) FileMetadataByLocation(_ file.Location) (file.Metadata, error) {
   147  	return file.Metadata{
   148  		LinkDestination: "MOCK",
   149  	}, nil
   150  }
   151  
   152  func (r *mockResolver) HasPath(_ string) bool {
   153  	return true
   154  }
   155  
   156  func (r *mockResolver) FilesByPath(_ ...string) ([]file.Location, error) {
   157  	return r.getLocations()
   158  }
   159  
   160  func (r *mockResolver) FilesByGlob(_ ...string) ([]file.Location, error) {
   161  	return r.getLocations()
   162  }
   163  
   164  func (r *mockResolver) FilesByMIMEType(_ ...string) ([]file.Location, error) {
   165  	return r.getLocations()
   166  }
   167  
   168  func (r *mockResolver) FilesByExtension(_ ...string) ([]file.Location, error) {
   169  	return r.getLocations()
   170  }
   171  
   172  func (r *mockResolver) FilesByBasename(_ ...string) ([]file.Location, error) {
   173  	return r.getLocations()
   174  }
   175  
   176  func (r *mockResolver) FilesByBasenameGlob(_ ...string) ([]file.Location, error) {
   177  	return r.getLocations()
   178  }
   179  
   180  func (r *mockResolver) RelativeFileByPath(_ file.Location, path string) *file.Location {
   181  	l := file.NewLocation(path)
   182  	return &l
   183  }
   184  
   185  func (r *mockResolver) AllLocations() <-chan file.Location {
   186  	c := make(chan file.Location)
   187  	go func() {
   188  		defer close(c)
   189  		locations, _ := r.getLocations()
   190  		for _, location := range locations {
   191  			c <- location
   192  		}
   193  	}()
   194  	return c
   195  }