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)
57 }
58 output, err := yaml.Marshal(val)
59 if err != nil {
60 panic(err)
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 }
77
View as plain text