github.com/google/osv-scalibr@v0.4.1/guidedremediation/internal/manifest/python/requirements_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 python
    16  
    17  import (
    18  	"os"
    19  	"path/filepath"
    20  	"testing"
    21  
    22  	"deps.dev/util/resolve"
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/google/osv-scalibr/fs"
    25  	"github.com/google/osv-scalibr/guidedremediation/internal/manifest"
    26  	"github.com/google/osv-scalibr/guidedremediation/result"
    27  )
    28  
    29  func TestReadRequirements(t *testing.T) {
    30  	fsys := fs.DirFS("./testdata/requirements")
    31  	pypiRW, _ := GetRequirementsReadWriter()
    32  	got, err := pypiRW.Read("requirements.txt", fsys)
    33  	if err != nil {
    34  		t.Fatalf("error reading manifest: %v", err)
    35  	}
    36  	want := testManifest{
    37  		FilePath: "requirements.txt",
    38  		Root: resolve.Version{
    39  			VersionKey: resolve.VersionKey{
    40  				PackageKey: resolve.PackageKey{
    41  					System: resolve.PyPI,
    42  					Name:   "myproject",
    43  				},
    44  				VersionType: resolve.Concrete,
    45  				Version:     "1.0.0",
    46  			},
    47  		},
    48  		System: resolve.PyPI,
    49  		Requirements: []resolve.RequirementVersion{
    50  			{
    51  				VersionKey: resolve.VersionKey{
    52  					PackageKey: resolve.PackageKey{
    53  						System: resolve.PyPI,
    54  						Name:   "pytest",
    55  					},
    56  					VersionType: resolve.Requirement,
    57  				},
    58  			},
    59  			{
    60  				VersionKey: resolve.VersionKey{
    61  					PackageKey: resolve.PackageKey{
    62  						System: resolve.PyPI,
    63  						Name:   "pytest-cov",
    64  					},
    65  					VersionType: resolve.Requirement,
    66  				},
    67  			},
    68  			{
    69  				VersionKey: resolve.VersionKey{
    70  					PackageKey: resolve.PackageKey{
    71  						System: resolve.PyPI,
    72  						Name:   "beautifulsoup4",
    73  					},
    74  					VersionType: resolve.Requirement,
    75  				},
    76  			},
    77  
    78  			{
    79  				VersionKey: resolve.VersionKey{
    80  					PackageKey: resolve.PackageKey{
    81  						System: resolve.PyPI,
    82  						Name:   "docopt",
    83  					},
    84  					VersionType: resolve.Requirement,
    85  					Version:     "== 0.6.1",
    86  				},
    87  			},
    88  			{
    89  				VersionKey: resolve.VersionKey{
    90  					PackageKey: resolve.PackageKey{
    91  						System: resolve.PyPI,
    92  						Name:   "requests",
    93  					},
    94  					VersionType: resolve.Requirement,
    95  					Version:     ">= 2.8.1, == 2.8.*",
    96  				},
    97  			},
    98  
    99  			{
   100  				VersionKey: resolve.VersionKey{
   101  					PackageKey: resolve.PackageKey{
   102  						System: resolve.PyPI,
   103  						Name:   "keyring",
   104  					},
   105  					VersionType: resolve.Requirement,
   106  					Version:     ">= 4.1.1",
   107  				},
   108  			},
   109  			{
   110  				VersionKey: resolve.VersionKey{
   111  					PackageKey: resolve.PackageKey{
   112  						System: resolve.PyPI,
   113  						Name:   "coverage",
   114  					},
   115  					VersionType: resolve.Requirement,
   116  					Version:     "!= 3.5",
   117  				},
   118  			},
   119  
   120  			{
   121  				VersionKey: resolve.VersionKey{
   122  					PackageKey: resolve.PackageKey{
   123  						System: resolve.PyPI,
   124  						Name:   "Mopidy-Dirble",
   125  					},
   126  					VersionType: resolve.Requirement,
   127  					Version:     "~=1.1",
   128  				},
   129  			},
   130  		},
   131  		Groups: map[manifest.RequirementKey][]string{},
   132  	}
   133  	checkManifest(t, "Manifest", got, want)
   134  }
   135  
   136  func TestWriteRequirements(t *testing.T) {
   137  	rw, _ := GetRequirementsReadWriter()
   138  	fsys := fs.DirFS("./testdata/requirements")
   139  	manif, err := rw.Read("requirements.txt", fsys)
   140  	if err != nil {
   141  		t.Fatalf("error reading manifest: %v", err)
   142  	}
   143  
   144  	patches := []result.Patch{
   145  		{
   146  			PackageUpdates: []result.PackageUpdate{
   147  				{
   148  					Name:        "docopt",
   149  					VersionFrom: "==0.6.1",
   150  					VersionTo:   "==0.6.2",
   151  				},
   152  			},
   153  		},
   154  		{
   155  			PackageUpdates: []result.PackageUpdate{
   156  				{
   157  					Name:        "requests",
   158  					VersionFrom: ">=2.8.1,==2.8.*",
   159  					VersionTo:   ">=2.32.4,<3.0.0",
   160  				},
   161  			},
   162  		},
   163  		{
   164  			PackageUpdates: []result.PackageUpdate{
   165  				{
   166  					Name:        "mopidy-dirble",
   167  					VersionFrom: "~=1.1",
   168  					VersionTo:   ">=1.3.0,<2.0.0",
   169  				},
   170  			},
   171  		},
   172  	}
   173  	outDir := t.TempDir()
   174  	outFile := filepath.Join(outDir, "requirements.txt")
   175  
   176  	if err := rw.Write(manif, fsys, patches, outFile); err != nil {
   177  		t.Fatalf("failed to write requirements.txt: %v", err)
   178  	}
   179  
   180  	got, err := os.ReadFile(outFile)
   181  	if err != nil {
   182  		t.Fatalf("failed to read got requirements.txt: %v", err)
   183  	}
   184  	want, err := os.ReadFile(filepath.Join("./testdata/requirements", "want.requirements.txt"))
   185  	if err != nil {
   186  		t.Fatalf("failed to read want requirements.txt: %v", err)
   187  	}
   188  	if diff := cmp.Diff(want, got); diff != "" {
   189  		t.Errorf("requirements.txt (-want +got):\n%s", diff)
   190  	}
   191  }