github.com/google/osv-scalibr@v0.4.1/enricher/license/license_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 license_test
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	depsdevpb "deps.dev/api/v3"
    22  	"github.com/google/go-cmp/cmp"
    23  	"github.com/google/go-cmp/cmp/cmpopts"
    24  	"github.com/google/go-cpy/cpy"
    25  	"github.com/google/osv-scalibr/enricher"
    26  	"github.com/google/osv-scalibr/enricher/license"
    27  	"github.com/google/osv-scalibr/enricher/license/fakeclient"
    28  	"github.com/google/osv-scalibr/extractor"
    29  	"github.com/google/osv-scalibr/inventory"
    30  	"github.com/google/osv-scalibr/purl"
    31  	"google.golang.org/protobuf/proto"
    32  )
    33  
    34  func TestEnrich(t *testing.T) {
    35  	cancelledContext, cancel := context.WithCancel(t.Context())
    36  	cancel()
    37  
    38  	copier := cpy.New(
    39  		cpy.Func(proto.Clone),
    40  		cpy.IgnoreAllUnexported(),
    41  	)
    42  
    43  	licenseMap := map[*depsdevpb.VersionKey][]string{
    44  		{System: depsdevpb.System_NPM, Name: "express", Version: "4.17.1"}:                 {"MIT"},
    45  		{System: depsdevpb.System_PYPI, Name: "requests", Version: "2.26.0"}:               {"Apache-2.0"},
    46  		{System: depsdevpb.System_GO, Name: "github.com/gin-gonic/gin", Version: "v1.8.1"}: {"MIT"},
    47  	}
    48  
    49  	cli := fakeclient.New(licenseMap)
    50  	e := license.NewWithClient(cli)
    51  
    52  	tests := []struct {
    53  		name     string
    54  		packages []*extractor.Package
    55  		//nolint:containedctx
    56  		ctx          context.Context
    57  		wantErr      error
    58  		wantPackages []*extractor.Package
    59  	}{
    60  		{
    61  			name:    "ctx_cancelled",
    62  			ctx:     cancelledContext,
    63  			wantErr: cmpopts.AnyError,
    64  			packages: []*extractor.Package{
    65  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM},
    66  				{Name: "requests", Version: "2.26.0", PURLType: purl.TypePyPi},
    67  				{Name: "github.com/gin-gonic/gin", Version: "1.8.1", PURLType: purl.TypeGolang},
    68  			},
    69  			wantPackages: []*extractor.Package{
    70  				// No license data
    71  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM},
    72  				{Name: "requests", Version: "2.26.0", PURLType: purl.TypePyPi},
    73  				{Name: "github.com/gin-gonic/gin", Version: "1.8.1", PURLType: purl.TypeGolang},
    74  			},
    75  		},
    76  		{
    77  			name: "simple_test",
    78  			packages: []*extractor.Package{
    79  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM},
    80  				{Name: "requests", Version: "2.26.0", PURLType: purl.TypePyPi},
    81  				{Name: "github.com/gin-gonic/gin", Version: "1.8.1", PURLType: purl.TypeGolang},
    82  			},
    83  			wantPackages: []*extractor.Package{
    84  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM, Licenses: []string{"MIT"}},
    85  				{Name: "requests", Version: "2.26.0", PURLType: purl.TypePyPi, Licenses: []string{"Apache-2.0"}},
    86  				{Name: "github.com/gin-gonic/gin", Version: "1.8.1", PURLType: purl.TypeGolang, Licenses: []string{"MIT"}},
    87  			},
    88  		},
    89  		{
    90  			name: "not_covered_purl_type",
    91  			packages: []*extractor.Package{
    92  				{Name: "fzf", Version: "0.63.0", PURLType: purl.TypeBrew},
    93  			},
    94  			wantPackages: []*extractor.Package{
    95  				// UNKNOWN license
    96  				{Name: "fzf", Version: "0.63.0", PURLType: purl.TypeBrew, Licenses: []string{"UNKNOWN"}},
    97  			},
    98  		},
    99  		{
   100  			name: "unknown_package",
   101  			packages: []*extractor.Package{
   102  				{Name: "unknown", Version: "1.8.1", PURLType: purl.TypeGolang},
   103  			},
   104  			wantPackages: []*extractor.Package{
   105  				// UNKNOWN license
   106  				{Name: "unknown", Version: "1.8.1", PURLType: purl.TypeGolang, Licenses: []string{"UNKNOWN"}},
   107  			},
   108  		},
   109  		{
   110  			name: "not_covered_pkg_with_already_a_license",
   111  			packages: []*extractor.Package{
   112  				{Name: "fzf", Version: "0.63.0", PURLType: purl.TypeBrew, Licenses: []string{"Apache-2.0"}},
   113  			},
   114  			wantPackages: []*extractor.Package{
   115  				{Name: "fzf", Version: "0.63.0", PURLType: purl.TypeBrew, Licenses: []string{"Apache-2.0"}},
   116  			},
   117  		},
   118  		{
   119  			name: "covered_pkg_with_already_a_license",
   120  			packages: []*extractor.Package{
   121  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM, Licenses: []string{"MIT"}},
   122  			},
   123  			wantPackages: []*extractor.Package{
   124  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM, Licenses: []string{"MIT"}},
   125  			},
   126  		},
   127  		{
   128  			name: "covered_pkg_with_wrong_license",
   129  			packages: []*extractor.Package{
   130  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM, Licenses: []string{"Apache-2.0"}},
   131  			},
   132  			wantPackages: []*extractor.Package{
   133  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM, Licenses: []string{"MIT"}},
   134  			},
   135  		},
   136  		{
   137  			name: "not_covered_purl_type_between_covered_pkgs",
   138  			packages: []*extractor.Package{
   139  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM},
   140  				{Name: "github.com/gin-gonic/gin", Version: "1.8.1", PURLType: purl.TypeGolang},
   141  				{Name: "fzf", Version: "0.63.0", PURLType: purl.TypeBrew},
   142  				{Name: "requests", Version: "2.26.0", PURLType: purl.TypePyPi},
   143  			},
   144  			wantPackages: []*extractor.Package{
   145  				{Name: "express", Version: "4.17.1", PURLType: purl.TypeNPM, Licenses: []string{"MIT"}},
   146  				{Name: "github.com/gin-gonic/gin", Version: "1.8.1", PURLType: purl.TypeGolang, Licenses: []string{"MIT"}},
   147  				{Name: "fzf", Version: "0.63.0", PURLType: purl.TypeBrew, Licenses: []string{"UNKNOWN"}},
   148  				{Name: "requests", Version: "2.26.0", PURLType: purl.TypePyPi, Licenses: []string{"Apache-2.0"}},
   149  			},
   150  		},
   151  	}
   152  
   153  	for _, tt := range tests {
   154  		t.Run(tt.name, func(t *testing.T) {
   155  			if tt.ctx == nil {
   156  				tt.ctx = t.Context()
   157  			}
   158  
   159  			var input *enricher.ScanInput
   160  
   161  			packages := copier.Copy(tt.packages).([]*extractor.Package)
   162  			inv := &inventory.Inventory{Packages: packages}
   163  
   164  			err := e.Enrich(tt.ctx, input, inv)
   165  			if !cmp.Equal(tt.wantErr, err, cmpopts.EquateErrors()) {
   166  				t.Fatalf("Enrich(%v) error: %v, want %v", tt.packages, err, tt.wantErr)
   167  			}
   168  
   169  			want := &inventory.Inventory{Packages: tt.wantPackages}
   170  			if diff := cmp.Diff(want, inv); diff != "" {
   171  				t.Errorf("Enrich(%v): unexpected diff (-want +got): %v", tt.packages, diff)
   172  			}
   173  		})
   174  	}
   175  }