github.com/google/osv-scalibr@v0.4.1/inventory/osvecosystem/parsed_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 osvecosystem_test contains tests for the osvecosystem package. 16 package osvecosystem_test 17 18 import ( 19 "encoding/json" 20 "reflect" 21 "testing" 22 23 "github.com/google/osv-scalibr/inventory/osvecosystem" 24 "github.com/ossf/osv-schema/bindings/go/osvconstants" 25 ) 26 27 type testCase struct { 28 string string 29 parsed osvecosystem.Parsed 30 } 31 32 func buildCases(t *testing.T) []testCase { 33 t.Helper() 34 35 return []testCase{ 36 { 37 string: "crates.io", 38 parsed: osvecosystem.Parsed{ 39 Ecosystem: osvconstants.EcosystemCratesIO, 40 Suffix: "", 41 }, 42 }, 43 { 44 string: "npm", 45 parsed: osvecosystem.Parsed{ 46 Ecosystem: osvconstants.EcosystemNPM, 47 Suffix: "", 48 }, 49 }, 50 { 51 string: "Debian: ", 52 parsed: osvecosystem.Parsed{ 53 Ecosystem: osvconstants.EcosystemDebian, 54 Suffix: " ", 55 }, 56 }, 57 { 58 string: "Debian::", 59 parsed: osvecosystem.Parsed{ 60 Ecosystem: osvconstants.EcosystemDebian, 61 Suffix: ":", 62 }, 63 }, 64 { 65 string: "Alpine", 66 parsed: osvecosystem.Parsed{ 67 Ecosystem: osvconstants.EcosystemAlpine, 68 Suffix: "", 69 }, 70 }, 71 { 72 string: "Alpine:v", 73 parsed: osvecosystem.Parsed{ 74 Ecosystem: osvconstants.EcosystemAlpine, 75 Suffix: "v", 76 }, 77 }, 78 { 79 string: "Alpine:v3.16", 80 parsed: osvecosystem.Parsed{ 81 Ecosystem: osvconstants.EcosystemAlpine, 82 Suffix: "v3.16", 83 }, 84 }, 85 { 86 string: "Alpine:3.16", 87 parsed: osvecosystem.Parsed{ 88 Ecosystem: osvconstants.EcosystemAlpine, 89 Suffix: "3.16", 90 }, 91 }, 92 { 93 string: "Maven", 94 parsed: osvecosystem.Parsed{ 95 Ecosystem: osvconstants.EcosystemMaven, 96 Suffix: "", 97 }, 98 }, 99 { 100 string: "Maven:https://maven.google.com", 101 parsed: osvecosystem.Parsed{ 102 Ecosystem: osvconstants.EcosystemMaven, 103 Suffix: "https://maven.google.com", 104 }, 105 }, 106 { 107 string: "Photon OS", 108 parsed: osvecosystem.Parsed{ 109 Ecosystem: osvconstants.EcosystemPhotonOS, 110 Suffix: "", 111 }, 112 }, 113 { 114 string: "Photon OS:abc", 115 parsed: osvecosystem.Parsed{ 116 Ecosystem: osvconstants.EcosystemPhotonOS, 117 Suffix: "abc", 118 }, 119 }, 120 { 121 string: "Photon OS:3.0", 122 parsed: osvecosystem.Parsed{ 123 Ecosystem: osvconstants.EcosystemPhotonOS, 124 Suffix: "3.0", 125 }, 126 }, 127 { 128 string: "Red Hat", 129 parsed: osvecosystem.Parsed{ 130 Ecosystem: osvconstants.EcosystemRedHat, 131 Suffix: "", 132 }, 133 }, 134 { 135 string: "Red Hat:abc", 136 parsed: osvecosystem.Parsed{ 137 Ecosystem: osvconstants.EcosystemRedHat, 138 Suffix: "abc", 139 }, 140 }, 141 { 142 string: "Red Hat:rhel_aus:8.4::appstream", 143 parsed: osvecosystem.Parsed{ 144 Ecosystem: osvconstants.EcosystemRedHat, 145 Suffix: "rhel_aus:8.4::appstream", 146 }, 147 }, 148 { 149 string: "Ubuntu", 150 parsed: osvecosystem.Parsed{ 151 Ecosystem: osvconstants.EcosystemUbuntu, 152 Suffix: "", 153 }, 154 }, 155 { 156 string: "Ubuntu:Pro", 157 parsed: osvecosystem.Parsed{ 158 Ecosystem: osvconstants.EcosystemUbuntu, 159 Suffix: "Pro", 160 }, 161 }, 162 { 163 string: "Ubuntu:Pro:18.04:LTS", 164 parsed: osvecosystem.Parsed{ 165 Ecosystem: osvconstants.EcosystemUbuntu, 166 Suffix: "Pro:18.04:LTS", 167 }, 168 }, 169 } 170 } 171 172 func TestParsed_UnmarshalJSON(t *testing.T) { 173 tests := buildCases(t) 174 for _, tt := range tests { 175 t.Run(tt.string, func(t *testing.T) { 176 var got osvecosystem.Parsed 177 178 if err := json.Unmarshal([]byte(`"`+tt.string+`"`), &got); err != nil { 179 t.Fatalf("Unmarshal() = %v; want no error", err) 180 } 181 182 // ensure that the string is unmarshalled into a struct 183 if !reflect.DeepEqual(got, tt.parsed) { 184 t.Errorf("Unmarshal() = %v; want %v", got, tt.parsed) 185 } 186 }) 187 } 188 } 189 190 func TestParsed_UnmarshalJSON_Errors(t *testing.T) { 191 tests := []struct { 192 input string 193 err string 194 }{ 195 {"1", "json: cannot unmarshal number into Go value of type string"}, 196 {"{}", "json: cannot unmarshal object into Go value of type string"}, 197 {"{\"ecosystem\": \"npm\"}", "json: cannot unmarshal object into Go value of type string"}, 198 {"{\"ecosystem\": \"npm\", \"suffix\": \"\"}", "json: cannot unmarshal object into Go value of type string"}, 199 {"{\"Ecosystem\": \"npm\", \"Suffix\": \"\"}", "json: cannot unmarshal object into Go value of type string"}, 200 {"[]", "json: cannot unmarshal array into Go value of type string"}, 201 } 202 for _, tt := range tests { 203 t.Run(tt.input, func(t *testing.T) { 204 var got osvecosystem.Parsed 205 err := json.Unmarshal([]byte(tt.input), &got) 206 207 if err == nil { 208 t.Fatalf("Unmarshal() = %v; want an error", err) 209 } 210 211 if err.Error() != tt.err { 212 t.Fatalf("Unmarshal() = %v; want %v", err.Error(), tt.err) 213 } 214 215 if got != (osvecosystem.Parsed{}) { 216 t.Fatalf("Unmarshal() = %v; want %v", got, osvecosystem.Parsed{}) 217 } 218 }) 219 } 220 } 221 222 func TestParsed_MarshalJSON(t *testing.T) { 223 tests := buildCases(t) 224 for _, tt := range tests { 225 t.Run(tt.string, func(t *testing.T) { 226 got, err := json.Marshal(tt.parsed) 227 228 if err != nil { 229 t.Fatalf("Marshal() = %v; want no error", err) 230 } 231 232 // ensure that the struct is marshaled as a string 233 want := `"` + tt.string + `"` 234 if string(got) != want { 235 t.Errorf("Marshal() = %v; want %v", string(got), want) 236 } 237 }) 238 } 239 } 240 241 func TestParsed_String(t *testing.T) { 242 tests := buildCases(t) 243 for _, tt := range tests { 244 t.Run(tt.string, func(t *testing.T) { 245 if got := tt.parsed.String(); got != tt.string { 246 t.Errorf("String() = %v, want %v", got, tt.string) 247 } 248 }) 249 } 250 } 251 252 func TestParse(t *testing.T) { 253 tests := buildCases(t) 254 for _, tt := range tests { 255 t.Run(tt.string, func(t *testing.T) { 256 if got := osvecosystem.MustParse(tt.string); !reflect.DeepEqual(got, tt.parsed) { 257 t.Errorf("Parse() = %v, want %v", got, tt.parsed) 258 } 259 }) 260 } 261 }