github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/addrs/target_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package addrs 5 6 import ( 7 "fmt" 8 "testing" 9 ) 10 11 func TestTargetContains(t *testing.T) { 12 for _, test := range []struct { 13 addr, other Targetable 14 expect bool 15 }{ 16 { 17 mustParseTarget("module.foo"), 18 mustParseTarget("module.bar"), 19 false, 20 }, 21 { 22 mustParseTarget("module.foo"), 23 mustParseTarget("module.foo"), 24 true, 25 }, 26 { 27 RootModuleInstance, 28 mustParseTarget("module.foo"), 29 true, 30 }, 31 { 32 mustParseTarget("module.foo"), 33 RootModuleInstance, 34 false, 35 }, 36 { 37 mustParseTarget("module.foo"), 38 mustParseTarget("module.foo.module.bar[0]"), 39 true, 40 }, 41 { 42 mustParseTarget("module.foo"), 43 mustParseTarget("module.foo.module.bar[0]"), 44 true, 45 }, 46 { 47 mustParseTarget("module.foo[2]"), 48 mustParseTarget("module.foo[2].module.bar[0]"), 49 true, 50 }, 51 { 52 mustParseTarget("module.foo"), 53 mustParseTarget("module.foo.test_resource.bar"), 54 true, 55 }, 56 { 57 mustParseTarget("module.foo"), 58 mustParseTarget("module.foo.test_resource.bar[0]"), 59 true, 60 }, 61 62 // Resources 63 { 64 mustParseTarget("test_resource.foo"), 65 mustParseTarget("test_resource.foo[\"bar\"]"), 66 true, 67 }, 68 { 69 mustParseTarget(`test_resource.foo["bar"]`), 70 mustParseTarget(`test_resource.foo["bar"]`), 71 true, 72 }, 73 { 74 mustParseTarget("test_resource.foo"), 75 mustParseTarget("test_resource.foo[2]"), 76 true, 77 }, 78 { 79 mustParseTarget("test_resource.foo"), 80 mustParseTarget("module.bar.test_resource.foo[2]"), 81 false, 82 }, 83 { 84 mustParseTarget("module.bar.test_resource.foo"), 85 mustParseTarget("module.bar.test_resource.foo[2]"), 86 true, 87 }, 88 { 89 mustParseTarget("module.bar.test_resource.foo"), 90 mustParseTarget("module.bar[0].test_resource.foo[2]"), 91 false, 92 }, 93 { 94 mustParseTarget("module.bar.test_resource.foo"), 95 mustParseTarget("module.bar.test_resource.foo[0]"), 96 true, 97 }, 98 { 99 mustParseTarget("module.bax"), 100 mustParseTarget("module.bax[0].test_resource.foo[0]"), 101 true, 102 }, 103 104 // Config paths, while never returned from parsing a target, must still 105 // be targetable 106 { 107 ConfigResource{ 108 Module: []string{"bar"}, 109 Resource: Resource{ 110 Mode: ManagedResourceMode, 111 Type: "test_resource", 112 Name: "foo", 113 }, 114 }, 115 mustParseTarget("module.bar.test_resource.foo[2]"), 116 true, 117 }, 118 { 119 mustParseTarget("module.bar"), 120 ConfigResource{ 121 Module: []string{"bar"}, 122 Resource: Resource{ 123 Mode: ManagedResourceMode, 124 Type: "test_resource", 125 Name: "foo", 126 }, 127 }, 128 true, 129 }, 130 { 131 mustParseTarget("module.bar.test_resource.foo"), 132 ConfigResource{ 133 Module: []string{"bar"}, 134 Resource: Resource{ 135 Mode: ManagedResourceMode, 136 Type: "test_resource", 137 Name: "foo", 138 }, 139 }, 140 true, 141 }, 142 { 143 ConfigResource{ 144 Resource: Resource{ 145 Mode: ManagedResourceMode, 146 Type: "test_resource", 147 Name: "foo", 148 }, 149 }, 150 mustParseTarget("module.bar.test_resource.foo[2]"), 151 false, 152 }, 153 { 154 ConfigResource{ 155 Module: []string{"bar"}, 156 Resource: Resource{ 157 Mode: ManagedResourceMode, 158 Type: "test_resource", 159 Name: "foo", 160 }, 161 }, 162 mustParseTarget("module.bar[0].test_resource.foo"), 163 true, 164 }, 165 166 // Modules are also never the result of parsing a target, but also need 167 // to be targetable 168 { 169 Module{"bar"}, 170 Module{"bar", "baz"}, 171 true, 172 }, 173 { 174 Module{"bar"}, 175 mustParseTarget("module.bar[0]"), 176 true, 177 }, 178 { 179 // Parsing an ambiguous module path needs to ensure the 180 // ModuleInstance could contain the Module. This is safe because if 181 // the module could be expanded, it must have an index, meaning no 182 // index indicates that the module instance and module are 183 // functionally equivalent. 184 mustParseTarget("module.bar"), 185 Module{"bar"}, 186 true, 187 }, 188 { 189 // A specific ModuleInstance cannot contain a module 190 mustParseTarget("module.bar[0]"), 191 Module{"bar"}, 192 false, 193 }, 194 { 195 Module{"bar", "baz"}, 196 mustParseTarget("module.bar[0].module.baz.test_resource.foo[1]"), 197 true, 198 }, 199 { 200 mustParseTarget("module.bar[0].module.baz"), 201 Module{"bar", "baz"}, 202 false, 203 }, 204 } { 205 t.Run(fmt.Sprintf("%s-in-%s", test.other, test.addr), func(t *testing.T) { 206 got := test.addr.TargetContains(test.other) 207 if got != test.expect { 208 t.Fatalf("expected %q.TargetContains(%q) == %t", test.addr, test.other, test.expect) 209 } 210 }) 211 } 212 } 213 214 func TestResourceContains(t *testing.T) { 215 for _, test := range []struct { 216 in, other Targetable 217 expect bool 218 }{} { 219 t.Run(fmt.Sprintf("%s-in-%s", test.other, test.in), func(t *testing.T) { 220 got := test.in.TargetContains(test.other) 221 if got != test.expect { 222 t.Fatalf("expected %q.TargetContains(%q) == %t", test.in, test.other, test.expect) 223 } 224 }) 225 } 226 } 227 228 func mustParseTarget(str string) Targetable { 229 t, diags := ParseTargetStr(str) 230 if diags != nil { 231 panic(fmt.Sprintf("%s: %s", str, diags.ErrWithWarnings())) 232 } 233 return t.Subject 234 }