github.com/google/osv-scalibr@v0.4.1/plugin/list/list_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package list_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/google/go-cmp/cmp"
    21  	"github.com/google/go-cmp/cmp/cmpopts"
    22  	cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
    23  	"github.com/google/osv-scalibr/plugin"
    24  	pl "github.com/google/osv-scalibr/plugin/list"
    25  )
    26  
    27  func TestExtractorNamesUnique(t *testing.T) {
    28  	all := pl.All(&cpb.PluginConfig{})
    29  	names := make(map[string]plugin.Plugin)
    30  	for _, e := range pl.FilesystemExtractors(all) {
    31  		if prev, ok := names[e.Name()]; ok {
    32  			t.Errorf("%q for Extractor %v already used by Extractor: %v", e.Name(), e, prev)
    33  		} else {
    34  			names[e.Name()] = e
    35  		}
    36  	}
    37  	for _, e := range pl.StandaloneExtractors(all) {
    38  		if prev, ok := names[e.Name()]; ok {
    39  			t.Errorf("%q for Extractor %v already used by Extractor: %v", e.Name(), e, prev)
    40  		} else {
    41  			names[e.Name()] = e
    42  		}
    43  	}
    44  }
    45  
    46  func TestDetectorNamesUnique(t *testing.T) {
    47  	all := pl.All(&cpb.PluginConfig{})
    48  	names := make(map[string]plugin.Plugin)
    49  	for _, d := range pl.Detectors(all) {
    50  		if prev, ok := names[d.Name()]; ok {
    51  			t.Errorf("%q for Detector %v already used by Detector: %v", d.Name(), d, prev)
    52  		} else {
    53  			names[d.Name()] = d
    54  		}
    55  	}
    56  }
    57  
    58  func TestAnnotatorNamesUnique(t *testing.T) {
    59  	all := pl.All(&cpb.PluginConfig{})
    60  	names := make(map[string]plugin.Plugin)
    61  	for _, a := range pl.Annotators(all) {
    62  		if prev, ok := names[a.Name()]; ok {
    63  			t.Errorf("%q for Annotator %v already used by Annotator: %v", a.Name(), a, prev)
    64  		} else {
    65  			names[a.Name()] = a
    66  		}
    67  	}
    68  }
    69  
    70  func TestEnricherNamesUnique(t *testing.T) {
    71  	all := pl.All(&cpb.PluginConfig{})
    72  	names := make(map[string]plugin.Plugin)
    73  	for _, e := range pl.Enrichers(all) {
    74  		if prev, ok := names[e.Name()]; ok {
    75  			t.Errorf("%q for Enricher %v already used by Enricher: %v", e.Name(), e, prev)
    76  		} else {
    77  			names[e.Name()] = e
    78  		}
    79  	}
    80  }
    81  
    82  func TestFromCapabilities(t *testing.T) {
    83  	capab := &plugin.Capabilities{OS: plugin.OSLinux}
    84  	want := []string{"os/snap", "weakcredentials/etcshadow"} // Available for Linux
    85  	dontWant := []string{"os/homebrew", "windows/dismpatch"} // Not available for Linux
    86  	plugins := pl.FromCapabilities(capab, &cpb.PluginConfig{})
    87  
    88  	for _, w := range want {
    89  		found := false
    90  		for _, p := range plugins {
    91  			if p.Name() == w {
    92  				found = true
    93  				break
    94  			}
    95  		}
    96  		if !found {
    97  			t.Errorf("pl.FromCapabilities(%v): %q not included in results, should be", capab, w)
    98  		}
    99  	}
   100  	for _, dw := range dontWant {
   101  		for _, p := range plugins {
   102  			if p.Name() == dw {
   103  				t.Errorf("pl.FromCapabilities(%v): %q included in results, shouldn't be", capab, dontWant)
   104  			}
   105  		}
   106  	}
   107  }
   108  
   109  func TestFromNames(t *testing.T) {
   110  	testCases := []struct {
   111  		desc      string
   112  		names     []string
   113  		wantNames []string
   114  		wantErr   error
   115  	}{
   116  		{
   117  			desc:      "Find_all_Plugins_of_a_type",
   118  			names:     []string{"python", "windows", "cis", "vex", "layerdetails"},
   119  			wantNames: []string{"python/pdmlock", "python/pipfilelock", "python/poetrylock", "python/pylock", "python/condameta", "python/uvlock", "python/wheelegg", "python/requirements", "python/setup", "windows/dismpatch", "cis/generic-linux/etcpasswdpermissions", "vex/cachedir", "vex/filter", "vex/os-duplicate/apk", "vex/os-duplicate/cos", "vex/os-duplicate/dpkg", "vex/os-duplicate/rpm", "vex/no-executable/dpkg", "baseimage"},
   120  		},
   121  		{
   122  			desc:      "Remove_duplicates",
   123  			names:     []string{"python", "python"},
   124  			wantNames: []string{"python/pdmlock", "python/pipfilelock", "python/poetrylock", "python/pylock", "python/condameta", "python/uvlock", "python/wheelegg", "python/requirements", "python/setup"},
   125  		},
   126  		{
   127  			desc:      "Nonexistent_plugin",
   128  			names:     []string{"nonexistent"},
   129  			wantErr:   cmpopts.AnyError,
   130  			wantNames: []string{},
   131  		},
   132  	}
   133  
   134  	for _, tc := range testCases {
   135  		t.Run(tc.desc, func(t *testing.T) {
   136  			got, err := pl.FromNames(tc.names, &cpb.PluginConfig{})
   137  			if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" {
   138  				t.Errorf("pl.FromNames(%v) error got diff (-want +got):\n%s", tc.names, diff)
   139  			}
   140  			gotNames := []string{}
   141  			for _, p := range got {
   142  				gotNames = append(gotNames, p.Name())
   143  			}
   144  			sort := func(p1, p2 string) bool { return p1 < p2 }
   145  			if diff := cmp.Diff(tc.wantNames, gotNames, cmpopts.SortSlices(sort)); diff != "" {
   146  				t.Errorf("pl.FromNames(%v): got diff (-want +got):\n%s", tc.names, diff)
   147  			}
   148  		})
   149  	}
   150  }
   151  
   152  func TestFromName(t *testing.T) {
   153  	testCases := []struct {
   154  		desc     string
   155  		name     string
   156  		wantName string
   157  		wantErr  error
   158  	}{
   159  		{
   160  			desc:     "Exact_name",
   161  			name:     "govulncheck/binary",
   162  			wantName: "govulncheck/binary",
   163  		},
   164  		{
   165  			desc:    "Nonexistent_plugin",
   166  			name:    "nonexistent",
   167  			wantErr: cmpopts.AnyError,
   168  		},
   169  		{
   170  			desc:    "Not_an_exact_name",
   171  			name:    "python",
   172  			wantErr: cmpopts.AnyError,
   173  		},
   174  	}
   175  
   176  	for _, tc := range testCases {
   177  		t.Run(tc.desc, func(t *testing.T) {
   178  			got, err := pl.FromName(tc.name, &cpb.PluginConfig{})
   179  			if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" {
   180  				t.Errorf("pl.FromName(%v) error got diff (-want +got):\n%s", tc.name, diff)
   181  			}
   182  			if err != nil {
   183  				return
   184  			}
   185  			if tc.wantName != got.Name() {
   186  				t.Errorf("pl.FromName(%s): want %s, got %s", tc.name, tc.wantName, got.Name())
   187  			}
   188  		})
   189  	}
   190  }