github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/runtime/nodejs/nodeversion/nodeversion_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 nodeversion_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"
    24  	"github.com/google/osv-scalibr/extractor/filesystem/runtime/nodejs/nodeversion"
    25  	"github.com/google/osv-scalibr/extractor/filesystem/runtime/nodejs/nodeversion/metadata"
    26  	"github.com/google/osv-scalibr/extractor/filesystem/simplefileapi"
    27  	"github.com/google/osv-scalibr/inventory"
    28  	"github.com/google/osv-scalibr/purl"
    29  	"github.com/google/osv-scalibr/testing/extracttest"
    30  )
    31  
    32  func TestFileRequired(t *testing.T) {
    33  	tests := []struct {
    34  		name         string
    35  		path         string
    36  		wantRequired bool
    37  	}{
    38  		{
    39  			name:         "valid .node-version file",
    40  			path:         "/project/.node-version",
    41  			wantRequired: true,
    42  		},
    43  		{
    44  			name:         "invalid path",
    45  			path:         "/tmp/var/scalibr",
    46  			wantRequired: false,
    47  		},
    48  		{
    49  			name:         "not node-version file",
    50  			path:         "/project/package.json",
    51  			wantRequired: false,
    52  		},
    53  	}
    54  	for _, tt := range tests {
    55  		t.Run(tt.name, func(t *testing.T) {
    56  			var e filesystem.Extractor = nodeversion.Extractor{}
    57  			if got := e.FileRequired(simplefileapi.New(tt.path, nil)); got != tt.wantRequired {
    58  				t.Fatalf("FileRequired(%s): got %v, want %v", tt.path, got, tt.wantRequired)
    59  			}
    60  		})
    61  	}
    62  }
    63  
    64  func TestExtract(t *testing.T) {
    65  	tests := []struct {
    66  		name            string
    67  		wantPackages    []*extractor.Package
    68  		inputConfigFile extracttest.ScanInputMockConfig
    69  	}{
    70  		{
    71  			name: "valid_.node-version_with_version",
    72  			inputConfigFile: extracttest.ScanInputMockConfig{
    73  				Path: "testdata/simpleValidWithComments.node-version",
    74  			},
    75  			wantPackages: []*extractor.Package{
    76  				{
    77  					Name:     "nodejs",
    78  					Version:  "20.1.0",
    79  					PURLType: purl.TypeGeneric,
    80  					Metadata: &metadata.Metadata{
    81  						NodeJsVersion: "20.1.0",
    82  					},
    83  					Locations: []string{"testdata/simpleValidWithComments.node-version"},
    84  				},
    85  			},
    86  		},
    87  		{
    88  			name: "valid_.node-version_with_whitespaces_and_comments",
    89  			inputConfigFile: extracttest.ScanInputMockConfig{
    90  				Path: "testdata/validWhiteSpaces.node-version",
    91  			},
    92  			wantPackages: []*extractor.Package{
    93  				{
    94  					Name:     "nodejs",
    95  					Version:  "24.04",
    96  					PURLType: purl.TypeGeneric,
    97  					Metadata: &metadata.Metadata{
    98  						NodeJsVersion: "24.04",
    99  					},
   100  					Locations: []string{"testdata/validWhiteSpaces.node-version"},
   101  				},
   102  			},
   103  		},
   104  		{
   105  			name: ".node-version_with_node_and_lts_instead_of_version",
   106  			inputConfigFile: extracttest.ScanInputMockConfig{
   107  				Path: "testdata/notNumericVersion.node-version",
   108  			},
   109  			wantPackages: nil,
   110  		},
   111  		{
   112  			name: ".node-version_with_no_numerical_version",
   113  			inputConfigFile: extracttest.ScanInputMockConfig{
   114  				Path: "testdata/validMultiVersionWithSkip.node-version",
   115  			},
   116  			wantPackages: nil,
   117  		},
   118  	}
   119  
   120  	for _, tt := range tests {
   121  		t.Run(tt.name, func(t *testing.T) {
   122  			extr := nodeversion.Extractor{}
   123  
   124  			scanInput := extracttest.GenerateScanInputMock(t, tt.inputConfigFile)
   125  			defer extracttest.CloseTestScanInput(t, scanInput)
   126  
   127  			got, _ := extr.Extract(t.Context(), &scanInput)
   128  
   129  			wantInv := inventory.Inventory{Packages: tt.wantPackages}
   130  			if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" {
   131  				t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.inputConfigFile.Path, diff)
   132  			}
   133  		})
   134  	}
   135  }