<commit_before>package morph

import (
	"math/big"
	"reflect"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/hashicorp/terraform-plugin-go/tftypes"
)

func TestMorphValueToType(t *testing.T) {
	type sampleInType struct {
		V tftypes.Value
		T tftypes.Type
	}
	samples := map[string]struct {
		In      sampleInType
		Out     tftypes.Value
		WantErr bool
	}{
		"string->string": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.String, "hello"),
				T: tftypes.String,
			},
			Out: tftypes.NewValue(tftypes.String, "hello"),
		},
		"string->number": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.String, "12.4"),
				T: tftypes.Number,
			},
			Out: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
		},
		"string->bool": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.String, "true"),
				T: tftypes.Bool,
			},
			Out: tftypes.NewValue(tftypes.Bool, true),
		},
		"number->number": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
				T: tftypes.Number,
			},
			Out: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
		},
		"number->string": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
				T: tftypes.String,
			},
			Out: tftypes.NewValue(tftypes.String, "12.4"),
		},
		"bool->bool": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Bool, true),
				T: tftypes.Bool,
			},
			Out: tftypes.NewValue(tftypes.Bool, true),
		},
		"bool->string": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Bool, true),
				T: tftypes.String,
			},
			Out: tftypes.NewValue(tftypes.String, "true"),
		},
		"list->list": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.List{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"list->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"list->set": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "10"),
					tftypes.NewValue(tftypes.String, "11.9"),
					tftypes.NewValue(tftypes.String, "42"),
				}),
				T: tftypes.Set{ElementType: tftypes.Number},
			},
			Out: tftypes.NewValue(tftypes.Set{ElementType: tftypes.Number}, []tftypes.Value{
				tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(10)),
				tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(11.9)),
				tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(42)),
			}),
		},
		"tuple->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		// This covers the case were we need to represent lists that contain dynamicPseudoType sub-elements
		// because the dynamicPseudoType might hold heterogenous types
		"tuple(single)->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.DynamicPseudoType}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.DynamicPseudoType, tftypes.DynamicPseudoType, tftypes.DynamicPseudoType}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"tuple->list": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.List{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"tuple->set": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Set{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"set->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"set->list": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.List{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),<commit_msg>Add null element case to morph unit test<commit_after>package morph

import (
	"math/big"
	"reflect"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/hashicorp/terraform-plugin-go/tftypes"
)

func TestMorphValueToType(t *testing.T) {
	type sampleInType struct {
		V tftypes.Value
		T tftypes.Type
	}
	samples := map[string]struct {
		In      sampleInType
		Out     tftypes.Value
		WantErr bool
	}{
		"string->string": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.String, "hello"),
				T: tftypes.String,
			},
			Out: tftypes.NewValue(tftypes.String, "hello"),
		},
		"string->number": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.String, "12.4"),
				T: tftypes.Number,
			},
			Out: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
		},
		"string->bool": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.String, "true"),
				T: tftypes.Bool,
			},
			Out: tftypes.NewValue(tftypes.Bool, true),
		},
		"number->number": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
				T: tftypes.Number,
			},
			Out: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
		},
		"number->string": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(12.4)),
				T: tftypes.String,
			},
			Out: tftypes.NewValue(tftypes.String, "12.4"),
		},
		"bool->bool": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Bool, true),
				T: tftypes.Bool,
			},
			Out: tftypes.NewValue(tftypes.Bool, true),
		},
		"bool->string": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Bool, true),
				T: tftypes.String,
			},
			Out: tftypes.NewValue(tftypes.String, "true"),
		},
		"list->list": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.List{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"list->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"list->set": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "10"),
					tftypes.NewValue(tftypes.String, "11.9"),
					tftypes.NewValue(tftypes.String, "42"),
				}),
				T: tftypes.Set{ElementType: tftypes.Number},
			},
			Out: tftypes.NewValue(tftypes.Set{ElementType: tftypes.Number}, []tftypes.Value{
				tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(10)),
				tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(11.9)),
				tftypes.NewValue(tftypes.Number, new(big.Float).SetFloat64(42)),
			}),
		},
		"tuple->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		// This covers the case were we need to represent lists that contain dynamicPseudoType sub-elements
		// because the dynamicPseudoType might hold heterogenous types
		"tuple(single)->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.DynamicPseudoType}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.DynamicPseudoType, tftypes.DynamicPseudoType, tftypes.DynamicPseudoType}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"tuple->list": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.List{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"tuple->set": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Set{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"tuple(object)->list(object)": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{
					tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}},
					tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.DynamicPseudoType}},
					tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}},
				}},
					[]tftypes.Value{
						tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}},
							map[string]tftypes.Value{"foo": tftypes.NewValue(tftypes.String, "foo")}),
						tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.DynamicPseudoType}},
							map[string]tftypes.Value{"foo": tftypes.NewValue(tftypes.DynamicPseudoType, nil)}),
						tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}},
							map[string]tftypes.Value{"foo": tftypes.NewValue(tftypes.String, "baz")}),
					}),
				T: tftypes.List{ElementType: tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}}},
			},
			Out: tftypes.NewValue(tftypes.List{ElementType: tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}}}, []tftypes.Value{
				tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}},
					map[string]tftypes.Value{"foo": tftypes.NewValue(tftypes.String, "foo")}),
				tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}},
					map[string]tftypes.Value{"foo": tftypes.NewValue(tftypes.String, nil)}),
				tftypes.NewValue(tftypes.Object{AttributeTypes: map[string]tftypes.Type{"foo": tftypes.String}},
					map[string]tftypes.Value{"foo": tftypes.NewValue(tftypes.String, "baz")}),
			}),
		},
		"set->tuple": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}},
			},
			Out: tftypes.NewValue(tftypes.Tuple{ElementTypes: []tftypes.Type{tftypes.String, tftypes.String, tftypes.String}}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
			}),
		},
		"set->list": {
			In: sampleInType{
				V: tftypes.NewValue(tftypes.Set{ElementType: tftypes.String}, []tftypes.Value{
					tftypes.NewValue(tftypes.String, "foo"),
					tftypes.NewValue(tftypes.String, "bar"),
					tftypes.NewValue(tftypes.String, "baz"),
				}),
				T: tftypes.List{ElementType: tftypes.String},
			},
			Out: tftypes.NewValue(tftypes.List{ElementType: tftypes.String}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "foo"),
				tftypes.NewValue(tftypes.String, "bar"),
				tftypes.NewValue(tftypes.String, "baz"),
{'fraction_non_alphanumeric': 0.17232422220910326, 'fraction_numerical': 0.005431253320739122, 'mean_word_length': 4.353982300884955, 'pattern_counts': {'":': 50, '<': 3, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5497709', 'n_tokens_mistral': 7719, 'n_tokens_neox': 6016, 'n_words': 829}