TestConvertStateDeterministic verifies that ConvertState produces identical output across multiple runs. This catches non-deterministic map iteration in the implementation. Unlike TestConvertStateGolden, this test does NOT sort the output — it relies on ConvertState itself being deterministic.
(t *testing.T)
| 134 | // this test does NOT sort the output — it relies on ConvertState itself |
| 135 | // being deterministic. |
| 136 | func TestConvertStateDeterministic(t *testing.T) { |
| 137 | t.Parallel() |
| 138 | |
| 139 | testResourceDirectories := filepath.Join("testdata", "resources") |
| 140 | entries, err := os.ReadDir(testResourceDirectories) |
| 141 | require.NoError(t, err) |
| 142 | |
| 143 | for _, testDirectory := range entries { |
| 144 | if !testDirectory.IsDir() { |
| 145 | continue |
| 146 | } |
| 147 | |
| 148 | testFiles, err := os.ReadDir(filepath.Join(testResourceDirectories, testDirectory.Name())) |
| 149 | require.NoError(t, err) |
| 150 | |
| 151 | for _, step := range []string{"plan", "state"} { |
| 152 | srcIdx := slices.IndexFunc(testFiles, func(entry os.DirEntry) bool { |
| 153 | return strings.HasSuffix(entry.Name(), fmt.Sprintf(".tf%s.json", step)) |
| 154 | }) |
| 155 | dotIdx := slices.IndexFunc(testFiles, func(entry os.DirEntry) bool { |
| 156 | return strings.HasSuffix(entry.Name(), fmt.Sprintf(".tf%s.dot", step)) |
| 157 | }) |
| 158 | |
| 159 | if srcIdx == -1 || dotIdx == -1 { |
| 160 | continue |
| 161 | } |
| 162 | |
| 163 | t.Run(step+"_"+testDirectory.Name(), func(t *testing.T) { |
| 164 | t.Parallel() |
| 165 | testDirectoryPath := filepath.Join(testResourceDirectories, testDirectory.Name()) |
| 166 | planFile := filepath.Join(testDirectoryPath, testFiles[srcIdx].Name()) |
| 167 | dotFile := filepath.Join(testDirectoryPath, testFiles[dotIdx].Name()) |
| 168 | |
| 169 | ctx := testutil.Context(t, testutil.WaitMedium) |
| 170 | logger := slogtest.Make(t, nil) |
| 171 | |
| 172 | tfStepRaw, err := os.ReadFile(planFile) |
| 173 | require.NoError(t, err) |
| 174 | |
| 175 | var modules []*tfjson.StateModule |
| 176 | switch step { |
| 177 | case "plan": |
| 178 | var tfPlan tfjson.Plan |
| 179 | err = json.Unmarshal(tfStepRaw, &tfPlan) |
| 180 | require.NoError(t, err) |
| 181 | modules = []*tfjson.StateModule{tfPlan.PlannedValues.RootModule} |
| 182 | if tfPlan.PriorState != nil { |
| 183 | modules = append(modules, tfPlan.PriorState.Values.RootModule) |
| 184 | } |
| 185 | case "state": |
| 186 | var tfState tfjson.State |
| 187 | err = json.Unmarshal(tfStepRaw, &tfState) |
| 188 | require.NoError(t, err) |
| 189 | modules = []*tfjson.StateModule{tfState.Values.RootModule} |
| 190 | default: |
| 191 | t.Fatalf("unknown step: %s", step) |
| 192 | } |
| 193 |
nothing calls this directly
no test coverage detected