github.com/terraform-linters/tflint@v0.51.2-0.20240520175844-3750771571b6/terraform/lang/function_calls_test.go (about) 1 package lang 2 3 import ( 4 "testing" 5 6 "github.com/google/go-cmp/cmp" 7 "github.com/hashicorp/hcl/v2" 8 "github.com/hashicorp/hcl/v2/hclsyntax" 9 "github.com/hashicorp/hcl/v2/json" 10 "github.com/terraform-linters/tflint-plugin-sdk/hclext" 11 "github.com/zclconf/go-cty/cty" 12 ) 13 14 func TestFunctionCallsInExpr(t *testing.T) { 15 parse := func(src string) hcl.Expression { 16 expr, diags := hclsyntax.ParseExpression([]byte(src), "", hcl.InitialPos) 17 if diags.HasErrors() { 18 t.Fatalf("failed to parse `%s`, %s", src, diags) 19 } 20 return expr 21 } 22 parseJSON := func(src string) hcl.Expression { 23 expr, diags := json.ParseExpression([]byte(src), "") 24 if diags.HasErrors() { 25 t.Fatalf("failed to parse `%s`, %s", src, diags) 26 } 27 return expr 28 } 29 30 tests := []struct { 31 name string 32 expr hcl.Expression 33 want []*FunctionCall 34 }{ 35 { 36 name: "nil expression", 37 expr: nil, 38 want: nil, 39 }, 40 { 41 name: "string", 42 expr: parse(`"string"`), 43 want: []*FunctionCall{}, 44 }, 45 { 46 name: "string (JSON)", 47 expr: parseJSON(`"string"`), 48 want: []*FunctionCall{}, 49 }, 50 { 51 name: "number (JSON)", 52 expr: parseJSON(`123`), 53 want: []*FunctionCall{}, 54 }, 55 { 56 name: "null (JSON)", 57 expr: parseJSON(`null`), 58 want: []*FunctionCall{}, 59 }, 60 { 61 name: "unknown (JSON)", 62 expr: parseJSON(`"${var.foo}"`), 63 want: []*FunctionCall{}, 64 }, 65 { 66 name: "single function call", 67 expr: parse(`md5("hello")`), 68 want: []*FunctionCall{ 69 {Name: "md5", ArgsCount: 1}, 70 }, 71 }, 72 { 73 name: "single function call (JSON)", 74 expr: parseJSON(`"${md5(\"hello\")}"`), 75 want: []*FunctionCall{ 76 {Name: "md5", ArgsCount: 1}, 77 }, 78 }, 79 { 80 name: "multiple function calls", 81 expr: parse(`[md5("hello"), "world", provider::tflint::world()]`), 82 want: []*FunctionCall{ 83 {Name: "md5", ArgsCount: 1}, 84 {Name: "provider::tflint::world", ArgsCount: 0}, 85 }, 86 }, 87 { 88 name: "multiple function calls (JSON)", 89 expr: parseJSON(`["${md5(\"hello\")}", "world", "${provider::tflint::world()}"]`), 90 want: []*FunctionCall{ 91 {Name: "md5", ArgsCount: 1}, 92 {Name: "provider::tflint::world", ArgsCount: 0}, 93 }, 94 }, 95 { 96 name: "bound expr with native syntax", 97 expr: hclext.BindValue(cty.StringVal("foo-Hello, John and Mike"), parse(`"foo-${hello("John", "Mike")}"`)), 98 want: []*FunctionCall{ 99 {Name: "hello", ArgsCount: 2}, 100 }, 101 }, 102 { 103 name: "bound expr with JSON syntax", 104 expr: hclext.BindValue(cty.StringVal("foo-Hello, John and Mike"), parseJSON(`"foo-${hello(\"John\", \"Mike\")}"`)), 105 want: []*FunctionCall{ 106 {Name: "hello", ArgsCount: 2}, 107 }, 108 }, 109 } 110 111 for _, test := range tests { 112 t.Run(test.name, func(t *testing.T) { 113 got, diags := FunctionCallsInExpr(test.expr) 114 if diags.HasErrors() { 115 t.Fatal(diags) 116 } 117 118 if diff := cmp.Diff(test.want, got); diff != "" { 119 t.Errorf(diff) 120 } 121 }) 122 } 123 } 124 125 func TestIsProviderDefined(t *testing.T) { 126 tests := []struct { 127 name string 128 want bool 129 }{ 130 { 131 name: "md5", 132 want: false, 133 }, 134 { 135 name: "core::md5", 136 want: false, 137 }, 138 { 139 name: "provider::tflint::echo", 140 want: true, 141 }, 142 } 143 144 for _, test := range tests { 145 t.Run(test.name, func(t *testing.T) { 146 f := &FunctionCall{Name: test.name} 147 148 got := f.IsProviderDefined() 149 150 if got != test.want { 151 t.Errorf("got %t, want %t", got, test.want) 152 } 153 }) 154 } 155 }