github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/internal/fileresolver/excluding_file_test.go (about)

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