github.com/google/osv-scalibr@v0.4.1/binary/proto/finding_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 proto_test 16 17 import ( 18 "errors" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/go-cpy/cpy" 23 "github.com/google/osv-scalibr/binary/proto" 24 spb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto" 25 "github.com/google/osv-scalibr/inventory" 26 "github.com/google/osv-scalibr/inventory/vex" 27 "google.golang.org/protobuf/testing/protocmp" 28 ) 29 30 var ( 31 genericFindingStruct1 = &inventory.GenericFinding{ 32 Adv: &inventory.GenericFindingAdvisory{ 33 ID: &inventory.AdvisoryID{ 34 Publisher: "CVE", 35 Reference: "CVE-1234", 36 }, 37 Title: "Title", 38 Description: "Description", 39 Recommendation: "Recommendation", 40 Sev: inventory.SeverityMedium, 41 }, 42 Target: &inventory.GenericFindingTargetDetails{ 43 Extra: "extra details", 44 }, 45 Plugins: []string{"cve/cve-1234-finder", "cve/cve-1234-enricher"}, 46 ExploitabilitySignals: []*vex.FindingExploitabilitySignal{{ 47 Plugin: "some-plugin", 48 Justification: vex.ComponentNotPresent, 49 }}, 50 } 51 52 genericFindingProto1 = &spb.GenericFinding{ 53 Adv: &spb.GenericFindingAdvisory{ 54 Id: &spb.AdvisoryId{ 55 Publisher: "CVE", 56 Reference: "CVE-1234", 57 }, 58 Title: "Title", 59 Description: "Description", 60 Recommendation: "Recommendation", 61 Sev: spb.SeverityEnum_MEDIUM, 62 }, 63 Target: &spb.GenericFindingTargetDetails{ 64 Extra: "extra details", 65 }, 66 Plugins: []string{"cve/cve-1234-finder", "cve/cve-1234-enricher"}, 67 ExploitabilitySignals: []*spb.FindingExploitabilitySignal{{ 68 Plugin: "some-plugin", 69 Justification: spb.VexJustification_COMPONENT_NOT_PRESENT, 70 }}, 71 } 72 ) 73 74 func TestGenericFindingToProto(t *testing.T) { 75 copier := cpy.New( 76 cpy.IgnoreAllUnexported(), 77 ) 78 79 testCases := []struct { 80 desc string 81 finding *inventory.GenericFinding 82 want *spb.GenericFinding 83 wantErr error 84 }{ 85 { 86 desc: "success", 87 finding: genericFindingStruct1, 88 want: genericFindingProto1, 89 }, 90 { 91 desc: "nil", 92 finding: nil, 93 want: nil, 94 }, 95 { 96 desc: "missing_advisory", 97 finding: func(f *inventory.GenericFinding) *inventory.GenericFinding { 98 f = copier.Copy(f).(*inventory.GenericFinding) 99 f.Adv = nil 100 return f 101 }(genericFindingStruct1), 102 want: nil, 103 wantErr: proto.ErrAdvisoryMissing, 104 }, 105 { 106 desc: "missing_advisory_ID", 107 finding: func(f *inventory.GenericFinding) *inventory.GenericFinding { 108 f = copier.Copy(f).(*inventory.GenericFinding) 109 f.Adv.ID = nil 110 return f 111 }(genericFindingStruct1), 112 want: nil, 113 wantErr: proto.ErrAdvisoryIDMissing, 114 }, 115 } 116 117 for _, tc := range testCases { 118 t.Run(tc.desc, func(t *testing.T) { 119 got, err := proto.GenericFindingToProto(tc.finding) 120 if !errors.Is(err, tc.wantErr) { 121 t.Errorf("GenericFindingToProto(%v) returned error %v, want error %v", tc.finding, err, tc.wantErr) 122 } 123 if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { 124 t.Fatalf("GenericFindingToProto(%v) returned diff (-want +got):\n%s", tc.finding, diff) 125 } 126 127 // No need to test the reverse conversion if the result is nil. 128 if got == nil { 129 return 130 } 131 132 // Test the reverse conversion for completeness. 133 gotPB, err := proto.GenericFindingToStruct(got) 134 if err != nil { 135 t.Fatalf("GenericFindingToStruct(%v) returned error %v, want nil", got, err) 136 } 137 if diff := cmp.Diff(tc.finding, gotPB, protocmp.Transform()); diff != "" { 138 t.Fatalf("GenericFindingToStruct(%v) returned diff (-want +got):\n%s", got, diff) 139 } 140 }) 141 } 142 } 143 144 func TestGenericFindingToStruct(t *testing.T) { 145 copier := cpy.New( 146 cpy.IgnoreAllUnexported(), 147 ) 148 149 testCases := []struct { 150 desc string 151 finding *spb.GenericFinding 152 want *inventory.GenericFinding 153 wantErr error 154 }{ 155 { 156 desc: "success", 157 finding: genericFindingProto1, 158 want: genericFindingStruct1, 159 }, 160 { 161 desc: "nil", 162 finding: nil, 163 want: nil, 164 }, 165 { 166 desc: "missing_advisory", 167 finding: func(f *spb.GenericFinding) *spb.GenericFinding { 168 f = copier.Copy(f).(*spb.GenericFinding) 169 f.Adv = nil 170 return f 171 }(genericFindingProto1), 172 want: nil, 173 wantErr: proto.ErrAdvisoryMissing, 174 }, 175 { 176 desc: "missing_advisory_ID", 177 finding: func(f *spb.GenericFinding) *spb.GenericFinding { 178 f = copier.Copy(f).(*spb.GenericFinding) 179 f.Adv.Id = nil 180 return f 181 }(genericFindingProto1), 182 want: nil, 183 wantErr: proto.ErrAdvisoryIDMissing, 184 }, 185 } 186 187 for _, tc := range testCases { 188 t.Run(tc.desc, func(t *testing.T) { 189 got, err := proto.GenericFindingToStruct(tc.finding) 190 if !errors.Is(err, tc.wantErr) { 191 t.Fatalf("GenericFindingToStruct(%v) returned error %v, want error %v", tc.finding, err, tc.wantErr) 192 } 193 if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { 194 t.Fatalf("GenericFindingToStruct(%v) returned diff (-want +got):\n%s", tc.finding, diff) 195 } 196 197 // No need to test the reverse conversion if the result is nil. 198 if got == nil { 199 return 200 } 201 202 // Test the reverse conversion for completeness. 203 gotPB, err := proto.GenericFindingToProto(got) 204 if err != nil { 205 t.Fatalf("GenericFindingToProto(%v) returned error %v, want nil", got, err) 206 } 207 if diff := cmp.Diff(tc.finding, gotPB, protocmp.Transform()); diff != "" { 208 t.Fatalf("GenericFindingToProto(%v) returned diff (-want +got):\n%s", got, diff) 209 } 210 }) 211 } 212 }