package s11n_test import ( "fmt" "testing" "github.com/aws-cloudformation/rain/cft/parse" "github.com/aws-cloudformation/rain/internal/s11n" "github.com/google/go-cmp/cmp" "gopkg.in/yaml.v3" ) func toNode(in interface{}) *yaml.Node { n := &yaml.Node{} err := n.Encode(in) if err != nil { panic(err) } return n } func get(in interface{}, path []interface{}) interface{} { if len(path) == 0 { return in } head, tail := path[0], path[1:] switch v := head.(type) { case string: return get(in.(map[string]interface{})[v], tail) case int: return get(in.([]interface{})[v], tail) default: panic(fmt.Errorf("Unexpected path entry: %#v", head)) } } func TestMatchPath(t *testing.T) { tplMap := map[string]interface{}{ "Parameters": map[string]interface{}{ "BucketName": map[string]interface{}{ "Type": "String", }, }, "Resources": map[string]interface{}{ "Bucket": map[string]interface{}{ "Type": "AWS::S3::Bucket", "Properties": map[string]interface{}{ "BucketName": map[string]interface{}{ "Ref": "BucketName", }, }, }, "Queue": map[string]interface{}{ "Type": "AWS::SQS::Queue", "Properties": map[string]interface{}{ "QueueName": map[string]interface{}{ "Ref": "BucketName", }, }, "Tags": []interface{}{ map[string]interface{}{ "Key": "First", "Value": "1", }, map[string]interface{}{ "Key": "Second", "Value": "2", }, }, }, }, "Outputs": map[string]interface{}{ "BucketName": map[string]interface{}{ "Value": map[string]interface{}{ "Ref": "Bucket", }, }, }, } testCases := []struct { path string expected []*yaml.Node }{ {path: "Parameters/BucketName", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Parameters", "BucketName"})), }}, {path: "Resources/*", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Resources", "Bucket"})), toNode(get(tplMap, []interface{}{"Resources", "Queue"})), }}, {path: "Resources/*/Tags/0", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Resources", "Queue", "Tags", 0})), }}, {path: "Resources/*/Properties", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Resources", "Bucket", "Properties"})), toNode(get(tplMap, []interface{}{"Resources", "Queue", "Properties"})), }}, {path: "Resources/*|Type==AWS::S3::Bucket/Properties", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Resources", "Bucket", "Properties"})), }}, {path: "Resources/*/Type", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Resources", "Bucket", "Type"})), toNode(get(tplMap, []interface{}{"Resources", "Queue", "Type"})), }}, {path: "**/Type", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Parameters", "BucketName", "Type"})), toNode(get(tplMap, []interface{}{"Resources", "Bucket", "Type"})), toNode(get(tplMap, []interface{}{"Resources", "Queue", "Type"})), }}, {path: "**/*|Ref", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Outputs", "BucketName", "Value"})), toNode(get(tplMap, []interface{}{"Resources", "Bucket", "Properties", "BucketName"})), toNode(get(tplMap, []interface{}{"Resources", "Queue", "Properties", "QueueName"})), }}, {path: "**/Tags/*|Key==Second/*", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Resources", "Queue", "Tags", 1, "Key"})), toNode(get(tplMap, []interface{}{"Resources", "Queue", "Tags", 1, "Value"})), }}, {path: "**/*|Tags", expected: []*yaml.Node{ toNode(get(tplMap, []interface{}{"Resources", "Queue"})), }}, } tpl, _ := parse.Map(tplMap) node := tpl.Node for _, testCase := range testCases { results := make([]*yaml.Node, 0) for n := range s11n.MatchAll(node, testCase.path) { results = append(results, n) } if len(results) != len(testCase.expected) { t.Errorf("%s: Expected %d results, got %d", testCase.path, len(testCase.expected), len(results)) } for i, actual := range results { expected := testCase.expected[i] if d := cmp.Diff(expected, actual); d != "" { t.Error(d) } } } }