github.com/google/osv-scalibr@v0.4.1/guidedremediation/internal/strategy/relax/relaxer/python_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 relaxer_test 16 17 import ( 18 "testing" 19 20 "deps.dev/util/resolve" 21 "github.com/google/osv-scalibr/guidedremediation/internal/strategy/relax/relaxer" 22 "github.com/google/osv-scalibr/guidedremediation/upgrade" 23 ) 24 25 func TestRelaxPython(t *testing.T) { 26 type result struct { 27 version string 28 ok bool 29 } 30 tests := []struct { 31 name string 32 versions []string 33 from string 34 upgradeConfig upgrade.Config 35 want result 36 }{ 37 { 38 name: "pinned version to pinned version", 39 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.3.0", "1.4.0", "2.0.0"}, 40 from: "==1.2.3", 41 upgradeConfig: upgrade.Config{"": upgrade.Major}, 42 want: result{ 43 version: "==1.2.5", 44 ok: true, 45 }, 46 }, 47 { 48 name: "relaxed pinned version disallowed", 49 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.3.0", "1.4.0", "2.0.0"}, 50 from: "==1.3.0", 51 upgradeConfig: upgrade.Config{"": upgrade.Patch}, 52 want: result{ 53 version: "==1.3.0", 54 ok: false, 55 }, 56 }, 57 { 58 name: "relax to compatible release", 59 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.3.0", "1.4.0", "2.0.0"}, 60 from: ">=1.2.3,<1.2.5", 61 upgradeConfig: upgrade.Config{"": upgrade.Major}, 62 want: result{ 63 version: "~=1.2.5", 64 ok: true, 65 }, 66 }, 67 { 68 name: "relax to version range", 69 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.3.0", "1.4.0", "2.0.0"}, 70 from: "~=1.2.3", 71 upgradeConfig: upgrade.Config{"": upgrade.Major}, 72 want: result{ 73 version: ">=1.3.0,<2.0.0", 74 ok: true, 75 }, 76 }, 77 { 78 name: "relax to a major version", 79 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.3.0", "1.4.0", "2.0.0"}, 80 from: ">=1.2.3,<2.0.0", 81 upgradeConfig: upgrade.Config{"": upgrade.Major}, 82 want: result{ 83 version: ">=2.0.0,<3.0.0", 84 ok: true, 85 }, 86 }, 87 { 88 name: "no newer version", 89 versions: []string{"1.2.3", "1.2.4", "1.2.5"}, 90 from: "~=1.2.5", 91 upgradeConfig: upgrade.Config{"": upgrade.Major}, 92 want: result{ 93 version: "~=1.2.5", 94 ok: false, 95 }, 96 }, 97 { 98 name: "skip the missing major", 99 versions: []string{"1.0.0", "3.0.0", "4.0.0"}, 100 from: "~=1.0.0", 101 upgradeConfig: upgrade.Config{"": upgrade.Major}, 102 want: result{ 103 version: ">=3.0.0,<4.0.0", 104 ok: true, 105 }, 106 }, 107 { 108 name: "skip pre-release", 109 versions: []string{"1.2.3", "2.0.0-alpha", "2.0.0", "3.0.0"}, 110 from: ">=1.0.0,<2.0.0", 111 upgradeConfig: upgrade.Config{"": upgrade.Major}, 112 want: result{ 113 version: ">=2.0.0,<3.0.0", 114 ok: true, 115 }, 116 }, 117 { 118 name: "avoid pre-release patch", 119 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.2.6-alpha"}, 120 from: ">=1.2.3,<1.2.5", 121 upgradeConfig: upgrade.Config{"": upgrade.Major}, 122 want: result{ 123 version: "~=1.2.5", 124 ok: true, 125 }, 126 }, 127 { 128 name: "avoid pre-release minor", 129 versions: []string{"1.2.3", "1.3.4", "1.4.5-alpha"}, 130 from: "~=1.2.3", 131 upgradeConfig: upgrade.Config{"": upgrade.Major}, 132 want: result{ 133 version: ">=1.3.4,<2.0.0", 134 ok: true, 135 }, 136 }, 137 { 138 name: "choose the latest pre-release", 139 versions: []string{"1.2.3", "2.0.0-alpha.0", "2.0.0-alpha.1", "2.0.0-beta"}, 140 from: ">=1.0.0,<2.0.0", 141 upgradeConfig: upgrade.Config{"": upgrade.Major}, 142 want: result{ 143 version: ">=2.0.0-beta,<3.0.0", 144 ok: true, 145 }, 146 }, 147 { 148 name: "relax from pre-release", 149 versions: []string{"1.0.0-pre", "1.2.3", "2.0.0-pre", "2.3.4"}, 150 from: ">=1.0.0-pre,<2.0.0", 151 upgradeConfig: upgrade.Config{"": upgrade.Major}, 152 want: result{ 153 version: ">=2.3.4,<3.0.0", 154 ok: true, 155 }, 156 }, 157 { 158 name: "upgrades not allowed", 159 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.3.0", "1.4.0", "2.0.0"}, 160 from: "==1.2.3", 161 upgradeConfig: upgrade.Config{"": upgrade.None}, 162 want: result{ 163 version: "==1.2.3", 164 ok: false, 165 }, 166 }, 167 { 168 name: "major upgrades not allowed", 169 versions: []string{"1.2.3", "1.2.4", "1.2.5", "1.3.0", "1.4.0", "2.0.0"}, 170 from: ">=1.2.3,<2.0.0", 171 upgradeConfig: upgrade.Config{"": upgrade.Minor}, 172 want: result{ 173 version: ">=1.2.3,<2.0.0", 174 ok: false, 175 }, 176 }, 177 } 178 179 for _, tt := range tests { 180 t.Run(tt.name, func(t *testing.T) { 181 cl := resolve.NewLocalClient() 182 pk := resolve.PackageKey{ 183 Name: "my-project", 184 System: resolve.PyPI, 185 } 186 for _, v := range tt.versions { 187 cl.AddVersion(resolve.Version{ 188 VersionKey: resolve.VersionKey{ 189 PackageKey: pk, 190 Version: v, 191 VersionType: resolve.Concrete, 192 }, 193 }, nil) 194 } 195 196 reqRelaxer := relaxer.PythonRelaxer{} 197 got, ok := reqRelaxer.Relax(t.Context(), cl, resolve.RequirementVersion{ 198 VersionKey: resolve.VersionKey{ 199 PackageKey: pk, 200 VersionType: resolve.Requirement, 201 Version: tt.from, 202 }}, tt.upgradeConfig) 203 if got.Version != tt.want.version || ok != tt.want.ok { 204 t.Errorf("Relax() = (%s, %v), want (%s, %v)", got.Version, ok, tt.want.version, tt.want.ok) 205 } 206 }) 207 } 208 }