github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/internal/lang/funcs/conversion_test.go (about)

     1  package funcs
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/eliastor/durgaform/internal/lang/marks"
     8  	"github.com/zclconf/go-cty/cty"
     9  )
    10  
    11  func TestTo(t *testing.T) {
    12  	tests := []struct {
    13  		Value    cty.Value
    14  		TargetTy cty.Type
    15  		Want     cty.Value
    16  		Err      string
    17  	}{
    18  		{
    19  			cty.StringVal("a"),
    20  			cty.String,
    21  			cty.StringVal("a"),
    22  			``,
    23  		},
    24  		{
    25  			cty.UnknownVal(cty.String),
    26  			cty.String,
    27  			cty.UnknownVal(cty.String),
    28  			``,
    29  		},
    30  		{
    31  			cty.NullVal(cty.String),
    32  			cty.String,
    33  			cty.NullVal(cty.String),
    34  			``,
    35  		},
    36  		{
    37  			// This test case represents evaluating the expression tostring(null)
    38  			// from HCL, since null in HCL is cty.NullVal(cty.DynamicPseudoType).
    39  			// The result in that case should still be null, but a null specifically
    40  			// of type string.
    41  			cty.NullVal(cty.DynamicPseudoType),
    42  			cty.String,
    43  			cty.NullVal(cty.String),
    44  			``,
    45  		},
    46  		{
    47  			cty.StringVal("a").Mark("boop"),
    48  			cty.String,
    49  			cty.StringVal("a").Mark("boop"),
    50  			``,
    51  		},
    52  		{
    53  			cty.NullVal(cty.String).Mark("boop"),
    54  			cty.String,
    55  			cty.NullVal(cty.String).Mark("boop"),
    56  			``,
    57  		},
    58  		{
    59  			cty.True,
    60  			cty.String,
    61  			cty.StringVal("true"),
    62  			``,
    63  		},
    64  		{
    65  			cty.StringVal("a"),
    66  			cty.Bool,
    67  			cty.DynamicVal,
    68  			`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
    69  		},
    70  		{
    71  			cty.StringVal("a").Mark("boop"),
    72  			cty.Bool,
    73  			cty.DynamicVal,
    74  			`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
    75  		},
    76  		{
    77  			cty.StringVal("a").Mark(marks.Sensitive),
    78  			cty.Bool,
    79  			cty.DynamicVal,
    80  			`cannot convert this sensitive string to bool`,
    81  		},
    82  		{
    83  			cty.StringVal("a"),
    84  			cty.Number,
    85  			cty.DynamicVal,
    86  			`cannot convert "a" to number; given string must be a decimal representation of a number`,
    87  		},
    88  		{
    89  			cty.StringVal("a").Mark("boop"),
    90  			cty.Number,
    91  			cty.DynamicVal,
    92  			`cannot convert "a" to number; given string must be a decimal representation of a number`,
    93  		},
    94  		{
    95  			cty.StringVal("a").Mark(marks.Sensitive),
    96  			cty.Number,
    97  			cty.DynamicVal,
    98  			`cannot convert this sensitive string to number`,
    99  		},
   100  		{
   101  			cty.NullVal(cty.String),
   102  			cty.Number,
   103  			cty.NullVal(cty.Number),
   104  			``,
   105  		},
   106  		{
   107  			cty.UnknownVal(cty.Bool),
   108  			cty.String,
   109  			cty.UnknownVal(cty.String),
   110  			``,
   111  		},
   112  		{
   113  			cty.UnknownVal(cty.String),
   114  			cty.Bool,
   115  			cty.UnknownVal(cty.Bool), // conversion is optimistic
   116  			``,
   117  		},
   118  		{
   119  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
   120  			cty.List(cty.String),
   121  			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
   122  			``,
   123  		},
   124  		{
   125  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
   126  			cty.Set(cty.String),
   127  			cty.SetVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
   128  			``,
   129  		},
   130  		{
   131  			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.True}),
   132  			cty.Map(cty.String),
   133  			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("true")}),
   134  			``,
   135  		},
   136  		{
   137  			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
   138  			cty.Map(cty.String),
   139  			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world").Mark("boop")}),
   140  			``,
   141  		},
   142  		{
   143  			cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
   144  			cty.Map(cty.String),
   145  			cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("world")}).Mark("boop"),
   146  			``,
   147  		},
   148  		{
   149  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
   150  			cty.List(cty.String),
   151  			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world").Mark("boop")}),
   152  			``,
   153  		},
   154  		{
   155  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
   156  			cty.List(cty.String),
   157  			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}).Mark("boop"),
   158  			``,
   159  		},
   160  		{
   161  			cty.EmptyTupleVal,
   162  			cty.String,
   163  			cty.DynamicVal,
   164  			`cannot convert tuple to string`,
   165  		},
   166  		{
   167  			cty.UnknownVal(cty.EmptyTuple),
   168  			cty.String,
   169  			cty.DynamicVal,
   170  			`cannot convert tuple to string`,
   171  		},
   172  		{
   173  			cty.EmptyObjectVal,
   174  			cty.Object(map[string]cty.Type{"foo": cty.String}),
   175  			cty.DynamicVal,
   176  			`incompatible object type for conversion: attribute "foo" is required`,
   177  		},
   178  	}
   179  
   180  	for _, test := range tests {
   181  		t.Run(fmt.Sprintf("to %s(%#v)", test.TargetTy.FriendlyNameForConstraint(), test.Value), func(t *testing.T) {
   182  			f := MakeToFunc(test.TargetTy)
   183  			got, err := f.Call([]cty.Value{test.Value})
   184  
   185  			if test.Err != "" {
   186  				if err == nil {
   187  					t.Fatal("succeeded; want error")
   188  				}
   189  				if got, want := err.Error(), test.Err; got != want {
   190  					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
   191  				}
   192  				return
   193  			} else if err != nil {
   194  				t.Fatalf("unexpected error: %s", err)
   195  			}
   196  
   197  			if !got.RawEquals(test.Want) {
   198  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   199  			}
   200  		})
   201  	}
   202  }