github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/os/rpm/metadata/metadata_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 metadata_test 16 17 import ( 18 "testing" 19 20 "github.com/google/go-cmp/cmp" 21 "github.com/google/osv-scalibr/extractor/filesystem/os/rpm/metadata" 22 "google.golang.org/protobuf/proto" 23 "google.golang.org/protobuf/testing/protocmp" 24 25 pb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto" 26 ) 27 28 func TestSetProto(t *testing.T) { 29 testCases := []struct { 30 desc string 31 m *metadata.Metadata 32 p *pb.Package 33 want *pb.Package 34 }{ 35 { 36 desc: "nil_metadata", 37 m: nil, 38 p: &pb.Package{Name: "some-package"}, 39 want: &pb.Package{Name: "some-package"}, 40 }, 41 { 42 desc: "nil_package", 43 m: &metadata.Metadata{ 44 PackageName: "name", 45 }, 46 p: nil, 47 want: nil, 48 }, 49 { 50 desc: "set_metadata", 51 m: &metadata.Metadata{ 52 PackageName: "name", 53 }, 54 p: &pb.Package{Name: "some-package"}, 55 want: &pb.Package{ 56 Name: "some-package", 57 Metadata: &pb.Package_RpmMetadata{ 58 RpmMetadata: &pb.RPMPackageMetadata{ 59 PackageName: "name", 60 }, 61 }, 62 }, 63 }, 64 { 65 desc: "override_metadata", 66 m: &metadata.Metadata{ 67 PackageName: "another-name", 68 }, 69 p: &pb.Package{ 70 Name: "some-package", 71 Metadata: &pb.Package_RpmMetadata{ 72 RpmMetadata: &pb.RPMPackageMetadata{ 73 PackageName: "name", 74 }, 75 }, 76 }, 77 want: &pb.Package{ 78 Name: "some-package", 79 Metadata: &pb.Package_RpmMetadata{ 80 RpmMetadata: &pb.RPMPackageMetadata{ 81 PackageName: "another-name", 82 }, 83 }, 84 }, 85 }, 86 { 87 desc: "set_all_fields", 88 m: &metadata.Metadata{ 89 PackageName: "name", 90 SourceRPM: "source-rpm", 91 Epoch: 1, 92 OSName: "os-name", 93 OSPrettyName: "os-pretty-name", 94 OSID: "os-id", 95 OSVersionID: "os-version-id", 96 OSBuildID: "os-build-id", 97 Vendor: "vendor", 98 Architecture: "architecture", 99 OSCPEName: "os-cpe-name", 100 }, 101 p: &pb.Package{Name: "some-package"}, 102 want: &pb.Package{ 103 Name: "some-package", 104 Metadata: &pb.Package_RpmMetadata{ 105 RpmMetadata: &pb.RPMPackageMetadata{ 106 PackageName: "name", 107 SourceRpm: "source-rpm", 108 Epoch: 1, 109 OsName: "os-name", 110 OsPrettyName: "os-pretty-name", 111 OsId: "os-id", 112 OsVersionId: "os-version-id", 113 OsBuildId: "os-build-id", 114 Vendor: "vendor", 115 Architecture: "architecture", 116 OsCpeName: "os-cpe-name", 117 }, 118 }, 119 }, 120 }, 121 } 122 123 for _, tc := range testCases { 124 t.Run(tc.desc, func(t *testing.T) { 125 p := proto.Clone(tc.p).(*pb.Package) 126 tc.m.SetProto(p) 127 opts := []cmp.Option{ 128 protocmp.Transform(), 129 } 130 if diff := cmp.Diff(tc.want, p, opts...); diff != "" { 131 t.Errorf("Metatadata{%+v}.SetProto(%+v): (-want +got):\n%s", tc.m, tc.p, diff) 132 } 133 134 // Test the reverse conversion for completeness. 135 136 if tc.p == nil && tc.want == nil { 137 return 138 } 139 140 got := metadata.ToStruct(p.GetRpmMetadata()) 141 if diff := cmp.Diff(tc.m, got); diff != "" { 142 t.Errorf("ToStruct(%+v): (-want +got):\n%s", p.GetRpmMetadata(), diff) 143 } 144 }) 145 } 146 } 147 148 func TestToStruct(t *testing.T) { 149 testCases := []struct { 150 desc string 151 m *pb.RPMPackageMetadata 152 want *metadata.Metadata 153 }{ 154 { 155 desc: "nil", 156 m: nil, 157 want: nil, 158 }, 159 { 160 desc: "some_fields", 161 m: &pb.RPMPackageMetadata{ 162 PackageName: "name", 163 }, 164 want: &metadata.Metadata{ 165 PackageName: "name", 166 }, 167 }, 168 { 169 desc: "all_fields", 170 m: &pb.RPMPackageMetadata{ 171 PackageName: "name", 172 SourceRpm: "source-rpm", 173 Epoch: 1, 174 OsName: "os-name", 175 OsPrettyName: "os-pretty-name", 176 OsId: "os-id", 177 OsVersionId: "os-version-id", 178 OsBuildId: "os-build-id", 179 Vendor: "vendor", 180 Architecture: "architecture", 181 OsCpeName: "os-cpe-name", 182 }, 183 want: &metadata.Metadata{ 184 PackageName: "name", 185 SourceRPM: "source-rpm", 186 Epoch: 1, 187 OSName: "os-name", 188 OSPrettyName: "os-pretty-name", 189 OSID: "os-id", 190 OSVersionID: "os-version-id", 191 OSBuildID: "os-build-id", 192 Vendor: "vendor", 193 Architecture: "architecture", 194 OSCPEName: "os-cpe-name", 195 }, 196 }, 197 } 198 199 for _, tc := range testCases { 200 t.Run(tc.desc, func(t *testing.T) { 201 got := metadata.ToStruct(tc.m) 202 if diff := cmp.Diff(tc.want, got); diff != "" { 203 t.Errorf("ToStruct(%+v): (-want +got):\n%s", tc.m, diff) 204 } 205 206 if tc.m == nil { 207 return 208 } 209 210 // Test the reverse conversion for completeness. 211 212 gotP := &pb.Package{} 213 wantP := &pb.Package{ 214 Metadata: &pb.Package_RpmMetadata{ 215 RpmMetadata: tc.m, 216 }, 217 } 218 got.SetProto(gotP) 219 opts := []cmp.Option{ 220 protocmp.Transform(), 221 } 222 if diff := cmp.Diff(wantP, gotP, opts...); diff != "" { 223 t.Errorf("Metatadata{%+v}.SetProto(%+v): (-want +got):\n%s", got, wantP, diff) 224 } 225 }) 226 } 227 } 228 229 func TestOpenEulerEcosystemSuffix(t *testing.T) { 230 testCases := []struct { 231 desc string 232 meta *metadata.Metadata 233 want string 234 }{ 235 { 236 desc: "base_version_from_pretty_name", 237 meta: &metadata.Metadata{ 238 OSPrettyName: "openEuler 24.03", 239 }, 240 want: "24.03", 241 }, 242 { 243 desc: "lts_qualifier", 244 meta: &metadata.Metadata{ 245 OSPrettyName: "openEuler 24.03 (LTS)", 246 }, 247 want: "24.03-LTS", 248 }, 249 { 250 desc: "lts_space_qualifier", 251 meta: &metadata.Metadata{ 252 OSPrettyName: "openEuler 24.03 (LTS SP1)", 253 }, 254 want: "24.03-LTS-SP1", 255 }, 256 { 257 desc: "lts_hyphen_qualifier", 258 meta: &metadata.Metadata{ 259 OSPrettyName: "openEuler 24.03 (LTS-SP1)", 260 }, 261 want: "24.03-LTS-SP1", 262 }, 263 { 264 desc: "fallback_to_version_id", 265 meta: &metadata.Metadata{ 266 OSVersionID: "24.03", 267 }, 268 want: "24.03", 269 }, 270 { 271 desc: "non_openEuler_pretty_name", 272 meta: &metadata.Metadata{ 273 OSPrettyName: "Fedora Linux 38 (Container Image)", 274 OSVersionID: "38", 275 }, 276 want: "38", 277 }, 278 { 279 desc: "no_details", 280 meta: &metadata.Metadata{}, 281 want: "", 282 }, 283 } 284 285 for _, tc := range testCases { 286 t.Run(tc.desc, func(t *testing.T) { 287 if got := tc.meta.OpenEulerEcosystemSuffix(); got != tc.want { 288 t.Fatalf("OpenEulerEcosystemSuffix() = %q, want %q", got, tc.want) 289 } 290 }) 291 } 292 }