sigs.k8s.io/cluster-api-provider-azure@v1.14.3/internal/test/matchers/gomega/matchers.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package gomega 18 19 import ( 20 "fmt" 21 "strings" 22 23 "github.com/google/go-cmp/cmp" 24 "github.com/onsi/gomega/matchers" 25 "github.com/onsi/gomega/types" 26 "sigs.k8s.io/cluster-api-provider-azure/internal/test/record" 27 ) 28 29 type ( 30 logEntryMatcher struct { 31 level *int 32 logFunc *string 33 values []interface{} 34 } 35 36 // LogMatcher is a Gomega matcher for logs. 37 LogMatcher interface { 38 types.GomegaMatcher 39 WithLevel(int) LogMatcher 40 WithLogFunc(string) LogMatcher 41 } 42 43 cmpMatcher struct { 44 x interface{} 45 diff string 46 } 47 ) 48 49 // DiffEq will verify cmp.Diff(expected, actual) == "" using github.com/google/go-cmp/cmp. 50 func DiffEq(x interface{}) types.GomegaMatcher { 51 return &cmpMatcher{ 52 x: x, 53 } 54 } 55 56 // Match returns whether the actual value matches the expected value. 57 func (c *cmpMatcher) Match(actual interface{}) (bool, error) { 58 c.diff = cmp.Diff(actual, c.x) 59 return c.diff == "", nil 60 } 61 62 // FailWithMessage returns the matcher's diff as the failure message. 63 func (c *cmpMatcher) FailureMessage(_ interface{}) string { 64 return c.diff 65 } 66 67 // NegatedFailureMessage return the matcher's diff as the negated failure message. 68 func (c *cmpMatcher) NegatedFailureMessage(_ interface{}) string { 69 return c.diff 70 } 71 72 // LogContains verifies that LogEntry matches the specified values. 73 func LogContains(values ...interface{}) LogMatcher { 74 return &logEntryMatcher{ 75 values: values, 76 } 77 } 78 79 // WithLevel sets the log level to that specified. 80 func (l *logEntryMatcher) WithLevel(level int) LogMatcher { 81 l.level = &level 82 return l 83 } 84 85 // WithLogFunc sets the log function to that specified. 86 func (l *logEntryMatcher) WithLogFunc(logFunc string) LogMatcher { 87 l.logFunc = &logFunc 88 return l 89 } 90 91 // Match returns whether the actual value matches the expected value. 92 func (l *logEntryMatcher) Match(actual interface{}) (bool, error) { 93 logEntry, ok := actual.(record.LogEntry) 94 if !ok { 95 return false, fmt.Errorf("LogContains matcher expects an record.LogEntry") 96 } 97 return len(l.validate(logEntry)) == 0, nil 98 } 99 100 // FailureMessage returns the specified value as a failure message. 101 func (l *logEntryMatcher) FailureMessage(actual interface{}) string { 102 return failMessage(l.validate(actual)) 103 } 104 105 // NegatedFailureMessage returns the specified value as a negated failure message. 106 func (l *logEntryMatcher) NegatedFailureMessage(actual interface{}) string { 107 return failMessage(l.validate(actual)) 108 } 109 110 func (l *logEntryMatcher) validate(actual interface{}) []error { 111 logEntry, ok := actual.(record.LogEntry) 112 if !ok { 113 return []error{fmt.Errorf("expected record.LogEntry, but got %T", actual)} 114 } 115 116 var errs []error 117 containsValues := matchers.ContainElementsMatcher{Elements: l.values} 118 ok, err := containsValues.Match(logEntry.Values) 119 if err != nil || !ok { 120 errs = append(errs, fmt.Errorf("actual log values %q didn't match expected %q", logEntry.Values, l.values)) 121 } 122 123 if l.logFunc != nil && *l.logFunc != logEntry.LogFunc { 124 errs = append(errs, fmt.Errorf("actual log Func %q didn't match expected %q", logEntry.LogFunc, *l.logFunc)) 125 } 126 127 if l.level != nil && *l.level != logEntry.Level { 128 errs = append(errs, fmt.Errorf("actual log level %q didn't match expected %q", logEntry.Level, *l.level)) 129 } 130 131 return errs 132 } 133 134 func failMessage(errs []error) string { 135 errMsgs := make([]string, len(errs)) 136 for i, err := range errs { 137 errMsgs[i] = err.Error() 138 } 139 return fmt.Sprintf("LogEntry errors: %s", strings.Join(errMsgs, ", ")) 140 }