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 }