github.com/google/osv-scalibr@v0.4.1/veles/secrets/common/pair/pair_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 pair_test 16 17 import ( 18 "regexp" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/osv-scalibr/veles" 23 "github.com/google/osv-scalibr/veles/secrets/common/pair" 24 ) 25 26 type mockSecret struct { 27 Value string 28 } 29 30 // mock function to convert Pair to veles.Secret 31 func mockSecretFromPair(p pair.Pair) (veles.Secret, bool) { 32 return mockSecret{Value: string(p.A.Value) + "-" + string(p.B.Value)}, true 33 } 34 35 // mock function to convert Pair to veles.Secret 36 func mockSecretFromPartialPair(p pair.Pair) (veles.Secret, bool) { 37 if p.B == nil { 38 return mockSecret{Value: string(p.A.Value)}, true 39 } 40 return mockSecret{Value: string(p.B.Value)}, true 41 } 42 43 func TestFindOptimalPairs(t *testing.T) { 44 var ( 45 aPattern = regexp.MustCompile(`a[a-z]*[1-9]`) 46 bPattern = regexp.MustCompile(`b[a-z]*[1-9]`) 47 ) 48 49 const distanceUpperBound = 1000 50 51 tests := []struct { 52 name string 53 input string 54 wantSecrets []veles.Secret 55 maxDistance uint32 56 wantPos []int 57 fromPartialPair func(pair.Pair) (veles.Secret, bool) 58 }{ 59 { 60 name: "simple match", 61 input: "a1 b1", 62 maxDistance: distanceUpperBound, 63 wantSecrets: []veles.Secret{ 64 mockSecret{Value: "a1-b1"}, 65 }, 66 wantPos: []int{0}, 67 }, 68 { 69 name: "multiple matches, greedy selection", 70 input: "a1 b1 a2 b2", 71 maxDistance: distanceUpperBound, 72 wantSecrets: []veles.Secret{ 73 mockSecret{Value: "a1-b1"}, 74 mockSecret{Value: "a2-b2"}, 75 }, 76 wantPos: []int{0, 6}, 77 }, 78 { 79 name: "no matches", 80 input: "a1 xxxxx", 81 }, 82 { 83 name: "more bs than as - deduplication", 84 input: "a1 b1 b2", 85 maxDistance: distanceUpperBound, 86 wantSecrets: []veles.Secret{ 87 mockSecret{Value: "a1-b1"}, 88 }, 89 wantPos: []int{0}, 90 }, 91 { 92 name: "far apart - no match", 93 input: "a1 b2", 94 maxDistance: uint32(5), 95 }, 96 { 97 name: "overlapping pairs", 98 input: " b2 ab1", 99 maxDistance: distanceUpperBound, 100 wantSecrets: []veles.Secret{ 101 mockSecret{Value: "ab1-b2"}, 102 }, 103 wantPos: []int{1}, 104 }, 105 { 106 name: "partial pair", 107 input: "a1", 108 maxDistance: distanceUpperBound, 109 fromPartialPair: mockSecretFromPartialPair, 110 wantSecrets: []veles.Secret{ 111 mockSecret{Value: "a1"}, 112 }, 113 wantPos: []int{0}, 114 }, 115 } 116 117 for _, tt := range tests { 118 t.Run(tt.name, func(t *testing.T) { 119 d := &pair.Detector{ 120 // include the whole payload using an upper bound as MaxElementLen 121 MaxElementLen: 10, MaxDistance: tt.maxDistance, 122 FindA: pair.FindAllMatches(aPattern), 123 FindB: pair.FindAllMatches(bPattern), 124 FromPair: mockSecretFromPair, 125 FromPartialPair: tt.fromPartialPair, 126 } 127 128 gotSecrets, gotPos := d.Detect([]byte(tt.input)) 129 if diff := cmp.Diff(tt.wantSecrets, gotSecrets); diff != "" { 130 t.Errorf("Secrets mismatch (-want +got):\n%s", diff) 131 } 132 if diff := cmp.Diff(tt.wantPos, gotPos); diff != "" { 133 t.Errorf("Positions mismatch (-want +got):\n%s", diff) 134 } 135 }) 136 } 137 }