github.com/hashicorp/hcl/v2@v2.20.0/ext/dynblock/variables_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package dynblock
     5  
     6  import (
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/hcl/v2/hcldec"
    11  	"github.com/zclconf/go-cty/cty"
    12  
    13  	"github.com/davecgh/go-spew/spew"
    14  
    15  	"github.com/hashicorp/hcl/v2"
    16  	"github.com/hashicorp/hcl/v2/hclsyntax"
    17  )
    18  
    19  func TestVariables(t *testing.T) {
    20  	const src = `
    21  
    22  # We have some references to things inside the "val" attribute inside each
    23  # of our "b" blocks, which should be included in the result of WalkVariables
    24  # but not WalkExpandVariables.
    25  
    26  a {
    27    dynamic "b" {
    28      for_each = [for i, v in some_list_0: "${i}=${v},${baz}"]
    29      labels = ["${b.value} ${something_else_0}"]
    30      content {
    31        val = "${b.value} ${something_else_1}"
    32      }
    33    }
    34  }
    35  
    36  dynamic "a" {
    37    for_each = some_list_1
    38  
    39    content {
    40      b "foo" {
    41        val = "${a.value} ${something_else_2}"
    42      }
    43  
    44      dynamic "b" {
    45        for_each = some_list_2
    46        iterator = dyn_b
    47        labels = ["${a.value} ${dyn_b.value} ${b} ${something_else_3}"]
    48        content {
    49          val = "${a.value} ${dyn_b.value} ${something_else_4}"
    50        }
    51      }
    52    }
    53  }
    54  
    55  dynamic "a" {
    56    for_each = some_list_3
    57    iterator = dyn_a
    58  
    59    content {
    60      b "foo" {
    61        val = "${dyn_a.value} ${something_else_5}"
    62      }
    63  
    64      dynamic "b" {
    65        for_each = some_list_4
    66        labels = ["${dyn_a.value} ${b.value} ${a} ${something_else_6}"]
    67        content {
    68          val = "${dyn_a.value} ${b.value} ${something_else_7}"
    69        }
    70      }
    71    }
    72  }
    73  `
    74  
    75  	f, diags := hclsyntax.ParseConfig([]byte(src), "", hcl.Pos{})
    76  	if len(diags) != 0 {
    77  		t.Errorf("unexpected diagnostics during parse")
    78  		for _, diag := range diags {
    79  			t.Logf("- %s", diag)
    80  		}
    81  		return
    82  	}
    83  
    84  	spec := &hcldec.BlockListSpec{
    85  		TypeName: "a",
    86  		Nested: &hcldec.BlockMapSpec{
    87  			TypeName:   "b",
    88  			LabelNames: []string{"key"},
    89  			Nested: &hcldec.AttrSpec{
    90  				Name: "val",
    91  				Type: cty.String,
    92  			},
    93  		},
    94  	}
    95  
    96  	t.Run("WalkVariables", func(t *testing.T) {
    97  		traversals := VariablesHCLDec(f.Body, spec)
    98  		got := make([]string, len(traversals))
    99  		for i, traversal := range traversals {
   100  			got[i] = traversal.RootName()
   101  		}
   102  
   103  		// The block structure is traversed one level at a time, so the ordering
   104  		// here is reflecting first a pass of the root, then the first child
   105  		// under the root, then the first child under that, etc.
   106  		want := []string{
   107  			"some_list_1",
   108  			"some_list_3",
   109  			"some_list_0",
   110  			"baz",
   111  			"something_else_0",
   112  			"something_else_1", // Would not be included for WalkExpandVariables because it only appears in content
   113  			"some_list_2",
   114  			"b", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_b
   115  			"something_else_3",
   116  			"something_else_2", // Would not be included for WalkExpandVariables because it only appears in content
   117  			"something_else_4", // Would not be included for WalkExpandVariables because it only appears in content
   118  			"some_list_4",
   119  			"a", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_a
   120  			"something_else_6",
   121  			"something_else_5", // Would not be included for WalkExpandVariables because it only appears in content
   122  			"something_else_7", // Would not be included for WalkExpandVariables because it only appears in content
   123  		}
   124  
   125  		if !reflect.DeepEqual(got, want) {
   126  			t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
   127  		}
   128  	})
   129  
   130  	t.Run("WalkExpandVariables", func(t *testing.T) {
   131  		traversals := ExpandVariablesHCLDec(f.Body, spec)
   132  		got := make([]string, len(traversals))
   133  		for i, traversal := range traversals {
   134  			got[i] = traversal.RootName()
   135  		}
   136  
   137  		// The block structure is traversed one level at a time, so the ordering
   138  		// here is reflecting first a pass of the root, then the first child
   139  		// under the root, then the first child under that, etc.
   140  		want := []string{
   141  			"some_list_1",
   142  			"some_list_3",
   143  			"some_list_0",
   144  			"baz",
   145  			"something_else_0",
   146  			"some_list_2",
   147  			"b", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_b
   148  			"something_else_3",
   149  			"some_list_4",
   150  			"a", // This is correct because it is referenced in a context where the iterator is overridden to be dyn_a
   151  			"something_else_6",
   152  		}
   153  
   154  		if !reflect.DeepEqual(got, want) {
   155  			t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
   156  		}
   157  	})
   158  }