github.com/opentofu/opentofu@v1.7.1/internal/moduledeps/module_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package moduledeps
     7  
     8  import (
     9  	"fmt"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/opentofu/opentofu/internal/addrs"
    14  	"github.com/opentofu/opentofu/internal/plugin/discovery"
    15  )
    16  
    17  func TestModuleWalkTree(t *testing.T) {
    18  	type walkStep struct {
    19  		Path       []string
    20  		ParentName string
    21  	}
    22  
    23  	tests := []struct {
    24  		Root      *Module
    25  		WalkOrder []walkStep
    26  	}{
    27  		{
    28  			&Module{
    29  				Name:     "root",
    30  				Children: nil,
    31  			},
    32  			[]walkStep{
    33  				{
    34  					Path:       []string{"root"},
    35  					ParentName: "",
    36  				},
    37  			},
    38  		},
    39  		{
    40  			&Module{
    41  				Name: "root",
    42  				Children: []*Module{
    43  					{
    44  						Name: "child",
    45  					},
    46  				},
    47  			},
    48  			[]walkStep{
    49  				{
    50  					Path:       []string{"root"},
    51  					ParentName: "",
    52  				},
    53  				{
    54  					Path:       []string{"root", "child"},
    55  					ParentName: "root",
    56  				},
    57  			},
    58  		},
    59  		{
    60  			&Module{
    61  				Name: "root",
    62  				Children: []*Module{
    63  					{
    64  						Name: "child",
    65  						Children: []*Module{
    66  							{
    67  								Name: "grandchild",
    68  							},
    69  						},
    70  					},
    71  				},
    72  			},
    73  			[]walkStep{
    74  				{
    75  					Path:       []string{"root"},
    76  					ParentName: "",
    77  				},
    78  				{
    79  					Path:       []string{"root", "child"},
    80  					ParentName: "root",
    81  				},
    82  				{
    83  					Path:       []string{"root", "child", "grandchild"},
    84  					ParentName: "child",
    85  				},
    86  			},
    87  		},
    88  		{
    89  			&Module{
    90  				Name: "root",
    91  				Children: []*Module{
    92  					{
    93  						Name: "child1",
    94  						Children: []*Module{
    95  							{
    96  								Name: "grandchild1",
    97  							},
    98  						},
    99  					},
   100  					{
   101  						Name: "child2",
   102  						Children: []*Module{
   103  							{
   104  								Name: "grandchild2",
   105  							},
   106  						},
   107  					},
   108  				},
   109  			},
   110  			[]walkStep{
   111  				{
   112  					Path:       []string{"root"},
   113  					ParentName: "",
   114  				},
   115  				{
   116  					Path:       []string{"root", "child1"},
   117  					ParentName: "root",
   118  				},
   119  				{
   120  					Path:       []string{"root", "child1", "grandchild1"},
   121  					ParentName: "child1",
   122  				},
   123  				{
   124  					Path:       []string{"root", "child2"},
   125  					ParentName: "root",
   126  				},
   127  				{
   128  					Path:       []string{"root", "child2", "grandchild2"},
   129  					ParentName: "child2",
   130  				},
   131  			},
   132  		},
   133  	}
   134  
   135  	for i, test := range tests {
   136  		t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
   137  			wo := test.WalkOrder
   138  			test.Root.WalkTree(func(path []string, parent *Module, current *Module) error {
   139  				if len(wo) == 0 {
   140  					t.Fatalf("ran out of walk steps while expecting one for %#v", path)
   141  				}
   142  				step := wo[0]
   143  				wo = wo[1:]
   144  				if got, want := path, step.Path; !reflect.DeepEqual(got, want) {
   145  					t.Errorf("wrong path %#v; want %#v", got, want)
   146  				}
   147  				parentName := ""
   148  				if parent != nil {
   149  					parentName = parent.Name
   150  				}
   151  				if got, want := parentName, step.ParentName; got != want {
   152  					t.Errorf("wrong parent name %q; want %q", got, want)
   153  				}
   154  
   155  				if got, want := current.Name, path[len(path)-1]; got != want {
   156  					t.Errorf("mismatching current.Name %q and final path element %q", got, want)
   157  				}
   158  				return nil
   159  			})
   160  		})
   161  	}
   162  }
   163  
   164  func TestModuleSortChildren(t *testing.T) {
   165  	m := &Module{
   166  		Name: "root",
   167  		Children: []*Module{
   168  			{
   169  				Name: "apple",
   170  			},
   171  			{
   172  				Name: "zebra",
   173  			},
   174  			{
   175  				Name: "xylophone",
   176  			},
   177  			{
   178  				Name: "pig",
   179  			},
   180  		},
   181  	}
   182  
   183  	m.SortChildren()
   184  
   185  	want := []string{"apple", "pig", "xylophone", "zebra"}
   186  	var got []string
   187  	for _, c := range m.Children {
   188  		got = append(got, c.Name)
   189  	}
   190  
   191  	if !reflect.DeepEqual(want, got) {
   192  		t.Errorf("wrong order %#v; want %#v", want, got)
   193  	}
   194  }
   195  
   196  func TestModuleProviderRequirements(t *testing.T) {
   197  	m := &Module{
   198  		Name: "root",
   199  		Providers: Providers{
   200  			addrs.NewDefaultProvider("foo"): ProviderDependency{
   201  				Constraints: discovery.ConstraintStr(">=1.0.0").MustParse(),
   202  			},
   203  			addrs.NewDefaultProvider("baz"): ProviderDependency{
   204  				Constraints: discovery.ConstraintStr(">=3.0.0").MustParse(),
   205  			},
   206  		},
   207  	}
   208  
   209  	reqd := m.ProviderRequirements()
   210  	if len(reqd) != 2 {
   211  		t.Errorf("wrong number of elements in %#v; want 2", reqd)
   212  	}
   213  	if got, want := reqd["foo"].Versions.String(), ">=1.0.0"; got != want {
   214  		t.Errorf("wrong combination of versions for 'foo' %q; want %q", got, want)
   215  	}
   216  	if got, want := reqd["baz"].Versions.String(), ">=3.0.0"; got != want {
   217  		t.Errorf("wrong combination of versions for 'baz' %q; want %q", got, want)
   218  	}
   219  }