github.com/onsi/gomega@v1.32.0/matchers/match_yaml_matcher.go (about) 1 package matchers 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/onsi/gomega/format" 8 "gopkg.in/yaml.v3" 9 ) 10 11 type MatchYAMLMatcher struct { 12 YAMLToMatch interface{} 13 firstFailurePath []interface{} 14 } 15 16 func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) { 17 actualString, expectedString, err := matcher.toStrings(actual) 18 if err != nil { 19 return false, err 20 } 21 22 var aval interface{} 23 var eval interface{} 24 25 if err := yaml.Unmarshal([]byte(actualString), &aval); err != nil { 26 return false, fmt.Errorf("Actual '%s' should be valid YAML, but it is not.\nUnderlying error:%s", actualString, err) 27 } 28 if err := yaml.Unmarshal([]byte(expectedString), &eval); err != nil { 29 return false, fmt.Errorf("Expected '%s' should be valid YAML, but it is not.\nUnderlying error:%s", expectedString, err) 30 } 31 32 var equal bool 33 equal, matcher.firstFailurePath = deepEqual(aval, eval) 34 return equal, nil 35 } 36 37 func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) { 38 actualString, expectedString, _ := matcher.toNormalisedStrings(actual) 39 return formattedMessage(format.Message(actualString, "to match YAML of", expectedString), matcher.firstFailurePath) 40 } 41 42 func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) { 43 actualString, expectedString, _ := matcher.toNormalisedStrings(actual) 44 return formattedMessage(format.Message(actualString, "not to match YAML of", expectedString), matcher.firstFailurePath) 45 } 46 47 func (matcher *MatchYAMLMatcher) toNormalisedStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) { 48 actualString, expectedString, err := matcher.toStrings(actual) 49 return normalise(actualString), normalise(expectedString), err 50 } 51 52 func normalise(input string) string { 53 var val interface{} 54 err := yaml.Unmarshal([]byte(input), &val) 55 if err != nil { 56 panic(err) // unreachable since Match already calls Unmarshal 57 } 58 output, err := yaml.Marshal(val) 59 if err != nil { 60 panic(err) // untested section, unreachable since we Unmarshal above 61 } 62 return strings.TrimSpace(string(output)) 63 } 64 65 func (matcher *MatchYAMLMatcher) toStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) { 66 actualString, ok := toString(actual) 67 if !ok { 68 return "", "", fmt.Errorf("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n%s", format.Object(actual, 1)) 69 } 70 expectedString, ok := toString(matcher.YAMLToMatch) 71 if !ok { 72 return "", "", fmt.Errorf("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n%s", format.Object(matcher.YAMLToMatch, 1)) 73 } 74 75 return actualString, expectedString, nil 76 }