github.com/google/osv-scalibr@v0.4.1/packageindex/package_index_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 packageindex_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/google/go-cmp/cmp"
    21  	"github.com/google/go-cmp/cmp/cmpopts"
    22  	"github.com/google/osv-scalibr/extractor"
    23  	"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/packagejson"
    24  	"github.com/google/osv-scalibr/extractor/filesystem/language/python/wheelegg"
    25  	"github.com/google/osv-scalibr/packageindex"
    26  	"github.com/google/osv-scalibr/purl"
    27  )
    28  
    29  var (
    30  	pkgLess = func(i1, i2 *extractor.Package) bool {
    31  		return i1.Name < i2.Name
    32  	}
    33  	sortPKGs        = cmpopts.SortSlices(pkgLess)
    34  	allowUnexported = cmp.AllowUnexported(packagejson.Extractor{}, wheelegg.Extractor{})
    35  )
    36  
    37  func TestGetAll(t *testing.T) {
    38  	pkgs := []*extractor.Package{
    39  		{Name: "software1", PURLType: purl.TypeNPM},
    40  		{Name: "software2", PURLType: purl.TypePyPi},
    41  		{Name: "software3", PURLType: purl.TypePyPi},
    42  		{Name: "software-no-purl"},
    43  	}
    44  	want := pkgs
    45  
    46  	px, err := packageindex.New(pkgs)
    47  	if err != nil {
    48  		t.Fatalf("packageindex.New(%v): %v", pkgs, err)
    49  	}
    50  
    51  	got := px.GetAll()
    52  	if diff := cmp.Diff(want, got, sortPKGs, allowUnexported); diff != "" {
    53  		t.Errorf("packageindex.New(%v).GetAll(): unexpected package (-want +got):\n%s", pkgs, diff)
    54  	}
    55  }
    56  
    57  func TestGetAllOfType(t *testing.T) {
    58  	pkgs := []*extractor.Package{
    59  		{Name: "software1", PURLType: purl.TypeNPM},
    60  		{Name: "software2", PURLType: purl.TypePyPi},
    61  		{Name: "software3", PURLType: purl.TypePyPi},
    62  		{Name: "software-no-purl"},
    63  	}
    64  	want := []*extractor.Package{
    65  		{Name: "software2", PURLType: purl.TypePyPi},
    66  		{Name: "software3", PURLType: purl.TypePyPi},
    67  	}
    68  
    69  	px, err := packageindex.New(pkgs)
    70  	if err != nil {
    71  		t.Fatalf("packageindex.New(%v): %v", pkgs, err)
    72  	}
    73  
    74  	got := px.GetAllOfType("pypi")
    75  	if diff := cmp.Diff(want, got, sortPKGs, allowUnexported); diff != "" {
    76  		t.Errorf("packageindex.New(%v).GetAllOfType(pypi): unexpected package (-want +got):\n%s", pkgs, diff)
    77  	}
    78  }
    79  
    80  func TestGetSpecific(t *testing.T) {
    81  	pkg1 := &extractor.Package{Name: "software1", Version: "1.2.3", PURLType: purl.TypeNPM}
    82  	pkg2 := &extractor.Package{Name: "software2", Version: "1.2.3", PURLType: purl.TypePyPi}
    83  	pkg3 := &extractor.Package{Name: "software3", PURLType: purl.TypePyPi}
    84  	pkg4v123 := &extractor.Package{Name: "software4", Version: "1.2.3", PURLType: purl.TypeNPM}
    85  	pkg4v456 := &extractor.Package{Name: "software4", Version: "4.5.6", PURLType: purl.TypeNPM}
    86  	pkgNoPURL := &extractor.Package{Name: "software-no-purl", Version: "1.2.3"}
    87  	pkgs := []*extractor.Package{pkg1, pkg2, pkg3, pkg4v123, pkg4v456, pkgNoPURL}
    88  
    89  	testCases := []struct {
    90  		desc    string
    91  		pkgType string
    92  		pkgName string
    93  		want    []*extractor.Package
    94  	}{
    95  		{
    96  			desc:    "No version or namespace",
    97  			pkgType: "pypi",
    98  			pkgName: "software3",
    99  			want:    []*extractor.Package{pkg3},
   100  		},
   101  		{
   102  			desc:    "software with version",
   103  			pkgType: "pypi",
   104  			pkgName: "software2",
   105  			want:    []*extractor.Package{pkg2},
   106  		},
   107  		{
   108  			desc:    "software with namespace",
   109  			pkgType: "npm",
   110  			pkgName: "software1",
   111  			want:    []*extractor.Package{pkg1},
   112  		},
   113  		{
   114  			desc:    "multiple versions",
   115  			pkgType: "npm",
   116  			pkgName: "software4",
   117  			want:    []*extractor.Package{pkg4v123, pkg4v456},
   118  		},
   119  		{
   120  			desc:    "no purl type",
   121  			pkgType: "",
   122  			pkgName: "software-no-purl",
   123  			want:    []*extractor.Package{pkgNoPURL},
   124  		},
   125  	}
   126  
   127  	for _, tc := range testCases {
   128  		t.Run(tc.desc, func(t *testing.T) {
   129  			px, err := packageindex.New(pkgs)
   130  			if err != nil {
   131  				t.Fatalf("packageindex.New(%v): %v", pkgs, err)
   132  			}
   133  
   134  			got := px.GetSpecific(tc.pkgName, tc.pkgType)
   135  			if diff := cmp.Diff(tc.want, got, sortPKGs, allowUnexported); diff != "" {
   136  				t.Errorf("packageindex.New(%v).GetSpecific(%s, %s): unexpected package (-want +got):\n%s", pkgs, tc.pkgName, tc.pkgType, diff)
   137  			}
   138  		})
   139  	}
   140  }