From 361741126871914de2e273dd5c5d715e7cd0090d Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Wed, 30 Aug 2023 08:49:32 -0700 Subject: [PATCH] hcldec: A test case for attributes set to cty.DynamicVal with refinements This test case is here to anticipate a _possible_ bug that isn't actually buggy in the current implementation: if an attribute spec is given a non-dynamic type constraint and then refined based on that type constraint then the hcldec implementation must perform the type conversion first and only then attempt to add the refinements. Another possible variation here would be for the attribute spec to have a dynamic type constraint (cty.DynamicPseudoType) and then try to refine its result. That case isn't tested here because that's always an implementation error in the calling application: RefineValueSpec must be used only in ways that are valid for the full range of types that the nested spec could produce, and there are no refinements that are valid for the full range of cty.DynamicPseudoType. That situation can and will panic at runtime, alerting the application developer that they've used hcldec incorrectly. There is no way for end-user input to cause this panic if the calling application is written correctly. This doesn't actually change the system behavior. It's a regression test to catch possible regressions under future maintenance. --- hcldec/spec_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hcldec/spec_test.go b/hcldec/spec_test.go index 093b032b..25c5d6cb 100644 --- a/hcldec/spec_test.go +++ b/hcldec/spec_test.go @@ -217,6 +217,7 @@ func TestRefineValueSpec(t *testing.T) { config := ` foo = "hello" bar = unk +dyn = dyn ` f, diags := hclsyntax.ParseConfig([]byte(config), "", hcl.InitialPos) @@ -257,11 +258,13 @@ bar = unk spec := &ObjectSpec{ "foo": attrSpec("foo"), "bar": attrSpec("bar"), + "dyn": attrSpec("dyn"), } got, diags := Decode(f.Body, spec, &hcl.EvalContext{ Variables: map[string]cty.Value{ "unk": cty.UnknownVal(cty.String), + "dyn": cty.DynamicVal, }, }) if diags.HasErrors() { @@ -276,6 +279,11 @@ bar = unk // The final value of bar is unknown but refined as non-null. "bar": cty.UnknownVal(cty.String).RefineNotNull(), + + // The final value of dyn is unknown but refined as non-null. + // Correct behavior here requires that we convert the DynamicVal + // to an unknown string first and then refine it. + "dyn": cty.UnknownVal(cty.String).RefineNotNull(), }) if diff := cmp.Diff(want, got, ctydebug.CmpOptions); diff != "" { t.Errorf("wrong result\n%s", diff)