github.com/hugorut/terraform@v1.1.3/src/lang/funcs/conversion_test.go (about)

     1  package funcs
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/hugorut/terraform/src/lang/marks"
     9  	"github.com/zclconf/go-cty/cty"
    10  )
    11  
    12  func TestTo(t *testing.T) {
    13  	tests := []struct {
    14  		Value    cty.Value
    15  		TargetTy cty.Type
    16  		Want     cty.Value
    17  		Err      string
    18  	}{
    19  		{
    20  			cty.StringVal("a"),
    21  			cty.String,
    22  			cty.StringVal("a"),
    23  			``,
    24  		},
    25  		{
    26  			cty.UnknownVal(cty.String),
    27  			cty.String,
    28  			cty.UnknownVal(cty.String),
    29  			``,
    30  		},
    31  		{
    32  			cty.NullVal(cty.String),
    33  			cty.String,
    34  			cty.NullVal(cty.String),
    35  			``,
    36  		},
    37  		{
    38  			cty.StringVal("a").Mark("boop"),
    39  			cty.String,
    40  			cty.StringVal("a").Mark("boop"),
    41  			``,
    42  		},
    43  		{
    44  			cty.NullVal(cty.String).Mark("boop"),
    45  			cty.String,
    46  			cty.NullVal(cty.String).Mark("boop"),
    47  			``,
    48  		},
    49  		{
    50  			cty.True,
    51  			cty.String,
    52  			cty.StringVal("true"),
    53  			``,
    54  		},
    55  		{
    56  			cty.StringVal("a"),
    57  			cty.Bool,
    58  			cty.DynamicVal,
    59  			`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
    60  		},
    61  		{
    62  			cty.StringVal("a").Mark("boop"),
    63  			cty.Bool,
    64  			cty.DynamicVal,
    65  			`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
    66  		},
    67  		{
    68  			cty.StringVal("a").Mark(marks.Sensitive),
    69  			cty.Bool,
    70  			cty.DynamicVal,
    71  			`cannot convert this sensitive string to bool`,
    72  		},
    73  		{
    74  			cty.StringVal("a"),
    75  			cty.Number,
    76  			cty.DynamicVal,
    77  			`cannot convert "a" to number; given string must be a decimal representation of a number`,
    78  		},
    79  		{
    80  			cty.StringVal("a").Mark("boop"),
    81  			cty.Number,
    82  			cty.DynamicVal,
    83  			`cannot convert "a" to number; given string must be a decimal representation of a number`,
    84  		},
    85  		{
    86  			cty.StringVal("a").Mark(marks.Sensitive),
    87  			cty.Number,
    88  			cty.DynamicVal,
    89  			`cannot convert this sensitive string to number`,
    90  		},
    91  		{
    92  			cty.NullVal(cty.String),
    93  			cty.Number,
    94  			cty.NullVal(cty.Number),
    95  			``,
    96  		},
    97  		{
    98  			cty.UnknownVal(cty.Bool),
    99  			cty.String,
   100  			cty.UnknownVal(cty.String),
   101  			``,
   102  		},
   103  		{
   104  			cty.UnknownVal(cty.String),
   105  			cty.Bool,
   106  			cty.UnknownVal(cty.Bool), // conversion is optimistic
   107  			``,
   108  		},
   109  		{
   110  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
   111  			cty.List(cty.String),
   112  			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
   113  			``,
   114  		},
   115  		{
   116  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
   117  			cty.Set(cty.String),
   118  			cty.SetVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
   119  			``,
   120  		},
   121  		{
   122  			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.True}),
   123  			cty.Map(cty.String),
   124  			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("true")}),
   125  			``,
   126  		},
   127  		{
   128  			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
   129  			cty.Map(cty.String),
   130  			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
   131  			``,
   132  		},
   133  		{
   134  			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
   135  			cty.Map(cty.String),
   136  			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
   137  			``,
   138  		},
   139  		{
   140  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
   141  			cty.List(cty.String),
   142  			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
   143  			``,
   144  		},
   145  		{
   146  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
   147  			cty.List(cty.String),
   148  			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
   149  			``,
   150  		},
   151  		{
   152  			cty.EmptyTupleVal,
   153  			cty.String,
   154  			cty.DynamicVal,
   155  			`cannot convert tuple to string`,
   156  		},
   157  		{
   158  			cty.UnknownVal(cty.EmptyTuple),
   159  			cty.String,
   160  			cty.DynamicVal,
   161  			`cannot convert tuple to string`,
   162  		},
   163  		{
   164  			cty.EmptyObjectVal,
   165  			cty.Object(map[string]cty.Type{"foo": cty.String}),
   166  			cty.DynamicVal,
   167  			`incompatible object type for conversion: attribute "foo" is required`,
   168  		},
   169  	}
   170  
   171  	for _, test := range tests {
   172  		t.Run(fmt.Sprintf("to %s(%#v)", test.TargetTy.FriendlyNameForConstraint(), test.Value), func(t *testing.T) {
   173  			f := MakeToFunc(test.TargetTy)
   174  			got, err := f.Call([]cty.Value{test.Value})
   175  
   176  			if test.Err != "" {
   177  				if err == nil {
   178  					t.Fatal("succeeded; want error")
   179  				}
   180  				if got, want := err.Error(), test.Err; got != want {
   181  					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
   182  				}
   183  				return
   184  			} else if err != nil {
   185  				t.Fatalf("unexpected error: %s", err)
   186  			}
   187  
   188  			if !got.RawEquals(test.Want) {
   189  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   190  			}
   191  		})
   192  	}
   193  }
   194  
   195  func TestType(t *testing.T) {
   196  	tests := []struct {
   197  		Input cty.Value
   198  		Want  string
   199  	}{
   200  		// Primititves
   201  		{
   202  			cty.StringVal("a"),
   203  			"string",
   204  		},
   205  		{
   206  			cty.NumberIntVal(42),
   207  			"number",
   208  		},
   209  		{
   210  			cty.BoolVal(true),
   211  			"bool",
   212  		},
   213  		// Collections
   214  		{
   215  			cty.EmptyObjectVal,
   216  			`object({})`,
   217  		},
   218  		{
   219  			cty.EmptyTupleVal,
   220  			`tuple([])`,
   221  		},
   222  		{
   223  			cty.ListValEmpty(cty.String),
   224  			`list(string)`,
   225  		},
   226  		{
   227  			cty.MapValEmpty(cty.String),
   228  			`map(string)`,
   229  		},
   230  		{
   231  			cty.SetValEmpty(cty.String),
   232  			`set(string)`,
   233  		},
   234  		{
   235  			cty.ListVal([]cty.Value{cty.StringVal("a")}),
   236  			`list(string)`,
   237  		},
   238  		{
   239  			cty.ListVal([]cty.Value{cty.ListVal([]cty.Value{cty.NumberIntVal(42)})}),
   240  			`list(list(number))`,
   241  		},
   242  		{
   243  			cty.ListVal([]cty.Value{cty.MapValEmpty(cty.String)}),
   244  			`list(map(string))`,
   245  		},
   246  		{
   247  			cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
   248  				"foo": cty.StringVal("bar"),
   249  			})}),
   250  			"list(\n    object({\n        foo: string,\n    }),\n)",
   251  		},
   252  		// Unknowns and Nulls
   253  		{
   254  			cty.UnknownVal(cty.String),
   255  			"string",
   256  		},
   257  		{
   258  			cty.NullVal(cty.Object(map[string]cty.Type{
   259  				"foo": cty.String,
   260  			})),
   261  			"object({\n    foo: string,\n})",
   262  		},
   263  		{ // irrelevant marks do nothing
   264  			cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
   265  				"foo": cty.StringVal("bar").Mark("ignore me"),
   266  			})}),
   267  			"list(\n    object({\n        foo: string,\n    }),\n)",
   268  		},
   269  	}
   270  	for _, test := range tests {
   271  		got, err := Type([]cty.Value{test.Input})
   272  		if err != nil {
   273  			t.Fatalf("unexpected error: %s", err)
   274  		}
   275  		// The value is marked to help with formatting
   276  		got, _ = got.Unmark()
   277  
   278  		if got.AsString() != test.Want {
   279  			t.Errorf("wrong result:\n%s", cmp.Diff(got.AsString(), test.Want))
   280  		}
   281  	}
   282  }