github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/command/views/test_test.go (about)

     1  package views
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/zclconf/go-cty/cty"
     9  
    10  	"github.com/terramate-io/tf/addrs"
    11  	"github.com/terramate-io/tf/command/arguments"
    12  	"github.com/terramate-io/tf/configs"
    13  	"github.com/terramate-io/tf/configs/configschema"
    14  	"github.com/terramate-io/tf/moduletest"
    15  	"github.com/terramate-io/tf/plans"
    16  	"github.com/terramate-io/tf/providers"
    17  	"github.com/terramate-io/tf/states"
    18  	"github.com/terramate-io/tf/terminal"
    19  	"github.com/terramate-io/tf/tfdiags"
    20  )
    21  
    22  func TestTestHuman_Conclusion(t *testing.T) {
    23  	tcs := map[string]struct {
    24  		Suite    *moduletest.Suite
    25  		Expected string
    26  	}{
    27  		"no tests": {
    28  			Suite:    &moduletest.Suite{},
    29  			Expected: "\nExecuted 0 tests.\n",
    30  		},
    31  
    32  		"only skipped tests": {
    33  			Suite: &moduletest.Suite{
    34  				Status: moduletest.Skip,
    35  				Files: map[string]*moduletest.File{
    36  					"descriptive_test_name.tftest.hcl": {
    37  						Name:   "descriptive_test_name.tftest.hcl",
    38  						Status: moduletest.Skip,
    39  						Runs: []*moduletest.Run{
    40  							{
    41  								Name:   "test_one",
    42  								Status: moduletest.Skip,
    43  							},
    44  							{
    45  								Name:   "test_two",
    46  								Status: moduletest.Skip,
    47  							},
    48  							{
    49  								Name:   "test_three",
    50  								Status: moduletest.Skip,
    51  							},
    52  						},
    53  					},
    54  					"other_descriptive_test_name.tftest.hcl": {
    55  						Name:   "other_descriptive_test_name.tftest.hcl",
    56  						Status: moduletest.Skip,
    57  						Runs: []*moduletest.Run{
    58  							{
    59  								Name:   "test_one",
    60  								Status: moduletest.Skip,
    61  							},
    62  							{
    63  								Name:   "test_two",
    64  								Status: moduletest.Skip,
    65  							},
    66  							{
    67  								Name:   "test_three",
    68  								Status: moduletest.Skip,
    69  							},
    70  						},
    71  					},
    72  				},
    73  			},
    74  			Expected: "\nExecuted 0 tests, 6 skipped.\n",
    75  		},
    76  
    77  		"only passed tests": {
    78  			Suite: &moduletest.Suite{
    79  				Status: moduletest.Pass,
    80  				Files: map[string]*moduletest.File{
    81  					"descriptive_test_name.tftest.hcl": {
    82  						Name:   "descriptive_test_name.tftest.hcl",
    83  						Status: moduletest.Pass,
    84  						Runs: []*moduletest.Run{
    85  							{
    86  								Name:   "test_one",
    87  								Status: moduletest.Pass,
    88  							},
    89  							{
    90  								Name:   "test_two",
    91  								Status: moduletest.Pass,
    92  							},
    93  							{
    94  								Name:   "test_three",
    95  								Status: moduletest.Pass,
    96  							},
    97  						},
    98  					},
    99  					"other_descriptive_test_name.tftest.hcl": {
   100  						Name:   "other_descriptive_test_name.tftest.hcl",
   101  						Status: moduletest.Pass,
   102  						Runs: []*moduletest.Run{
   103  							{
   104  								Name:   "test_one",
   105  								Status: moduletest.Pass,
   106  							},
   107  							{
   108  								Name:   "test_two",
   109  								Status: moduletest.Pass,
   110  							},
   111  							{
   112  								Name:   "test_three",
   113  								Status: moduletest.Pass,
   114  							},
   115  						},
   116  					},
   117  				},
   118  			},
   119  			Expected: "\nSuccess! 6 passed, 0 failed.\n",
   120  		},
   121  
   122  		"passed and skipped tests": {
   123  			Suite: &moduletest.Suite{
   124  				Status: moduletest.Pass,
   125  				Files: map[string]*moduletest.File{
   126  					"descriptive_test_name.tftest.hcl": {
   127  						Name:   "descriptive_test_name.tftest.hcl",
   128  						Status: moduletest.Pass,
   129  						Runs: []*moduletest.Run{
   130  							{
   131  								Name:   "test_one",
   132  								Status: moduletest.Pass,
   133  							},
   134  							{
   135  								Name:   "test_two",
   136  								Status: moduletest.Skip,
   137  							},
   138  							{
   139  								Name:   "test_three",
   140  								Status: moduletest.Pass,
   141  							},
   142  						},
   143  					},
   144  					"other_descriptive_test_name.tftest.hcl": {
   145  						Name:   "other_descriptive_test_name.tftest.hcl",
   146  						Status: moduletest.Pass,
   147  						Runs: []*moduletest.Run{
   148  							{
   149  								Name:   "test_one",
   150  								Status: moduletest.Skip,
   151  							},
   152  							{
   153  								Name:   "test_two",
   154  								Status: moduletest.Pass,
   155  							},
   156  							{
   157  								Name:   "test_three",
   158  								Status: moduletest.Pass,
   159  							},
   160  						},
   161  					},
   162  				},
   163  			},
   164  			Expected: "\nSuccess! 4 passed, 0 failed, 2 skipped.\n",
   165  		},
   166  
   167  		"only failed tests": {
   168  			Suite: &moduletest.Suite{
   169  				Status: moduletest.Fail,
   170  				Files: map[string]*moduletest.File{
   171  					"descriptive_test_name.tftest.hcl": {
   172  						Name:   "descriptive_test_name.tftest.hcl",
   173  						Status: moduletest.Fail,
   174  						Runs: []*moduletest.Run{
   175  							{
   176  								Name:   "test_one",
   177  								Status: moduletest.Fail,
   178  							},
   179  							{
   180  								Name:   "test_two",
   181  								Status: moduletest.Fail,
   182  							},
   183  							{
   184  								Name:   "test_three",
   185  								Status: moduletest.Fail,
   186  							},
   187  						},
   188  					},
   189  					"other_descriptive_test_name.tftest.hcl": {
   190  						Name:   "other_descriptive_test_name.tftest.hcl",
   191  						Status: moduletest.Fail,
   192  						Runs: []*moduletest.Run{
   193  							{
   194  								Name:   "test_one",
   195  								Status: moduletest.Fail,
   196  							},
   197  							{
   198  								Name:   "test_two",
   199  								Status: moduletest.Fail,
   200  							},
   201  							{
   202  								Name:   "test_three",
   203  								Status: moduletest.Fail,
   204  							},
   205  						},
   206  					},
   207  				},
   208  			},
   209  			Expected: "\nFailure! 0 passed, 6 failed.\n",
   210  		},
   211  
   212  		"failed and skipped tests": {
   213  			Suite: &moduletest.Suite{
   214  				Status: moduletest.Fail,
   215  				Files: map[string]*moduletest.File{
   216  					"descriptive_test_name.tftest.hcl": {
   217  						Name:   "descriptive_test_name.tftest.hcl",
   218  						Status: moduletest.Fail,
   219  						Runs: []*moduletest.Run{
   220  							{
   221  								Name:   "test_one",
   222  								Status: moduletest.Fail,
   223  							},
   224  							{
   225  								Name:   "test_two",
   226  								Status: moduletest.Skip,
   227  							},
   228  							{
   229  								Name:   "test_three",
   230  								Status: moduletest.Fail,
   231  							},
   232  						},
   233  					},
   234  					"other_descriptive_test_name.tftest.hcl": {
   235  						Name:   "other_descriptive_test_name.tftest.hcl",
   236  						Status: moduletest.Fail,
   237  						Runs: []*moduletest.Run{
   238  							{
   239  								Name:   "test_one",
   240  								Status: moduletest.Fail,
   241  							},
   242  							{
   243  								Name:   "test_two",
   244  								Status: moduletest.Fail,
   245  							},
   246  							{
   247  								Name:   "test_three",
   248  								Status: moduletest.Skip,
   249  							},
   250  						},
   251  					},
   252  				},
   253  			},
   254  			Expected: "\nFailure! 0 passed, 4 failed, 2 skipped.\n",
   255  		},
   256  
   257  		"failed, passed and skipped tests": {
   258  			Suite: &moduletest.Suite{
   259  				Status: moduletest.Fail,
   260  				Files: map[string]*moduletest.File{
   261  					"descriptive_test_name.tftest.hcl": {
   262  						Name:   "descriptive_test_name.tftest.hcl",
   263  						Status: moduletest.Fail,
   264  						Runs: []*moduletest.Run{
   265  							{
   266  								Name:   "test_one",
   267  								Status: moduletest.Fail,
   268  							},
   269  							{
   270  								Name:   "test_two",
   271  								Status: moduletest.Pass,
   272  							},
   273  							{
   274  								Name:   "test_three",
   275  								Status: moduletest.Skip,
   276  							},
   277  						},
   278  					},
   279  					"other_descriptive_test_name.tftest.hcl": {
   280  						Name:   "other_descriptive_test_name.tftest.hcl",
   281  						Status: moduletest.Fail,
   282  						Runs: []*moduletest.Run{
   283  							{
   284  								Name:   "test_one",
   285  								Status: moduletest.Skip,
   286  							},
   287  							{
   288  								Name:   "test_two",
   289  								Status: moduletest.Fail,
   290  							},
   291  							{
   292  								Name:   "test_three",
   293  								Status: moduletest.Pass,
   294  							},
   295  						},
   296  					},
   297  				},
   298  			},
   299  			Expected: "\nFailure! 2 passed, 2 failed, 2 skipped.\n",
   300  		},
   301  
   302  		"failed and errored tests": {
   303  			Suite: &moduletest.Suite{
   304  				Status: moduletest.Error,
   305  				Files: map[string]*moduletest.File{
   306  					"descriptive_test_name.tftest.hcl": {
   307  						Name:   "descriptive_test_name.tftest.hcl",
   308  						Status: moduletest.Error,
   309  						Runs: []*moduletest.Run{
   310  							{
   311  								Name:   "test_one",
   312  								Status: moduletest.Fail,
   313  							},
   314  							{
   315  								Name:   "test_two",
   316  								Status: moduletest.Error,
   317  							},
   318  							{
   319  								Name:   "test_three",
   320  								Status: moduletest.Fail,
   321  							},
   322  						},
   323  					},
   324  					"other_descriptive_test_name.tftest.hcl": {
   325  						Name:   "other_descriptive_test_name.tftest.hcl",
   326  						Status: moduletest.Error,
   327  						Runs: []*moduletest.Run{
   328  							{
   329  								Name:   "test_one",
   330  								Status: moduletest.Fail,
   331  							},
   332  							{
   333  								Name:   "test_two",
   334  								Status: moduletest.Error,
   335  							},
   336  							{
   337  								Name:   "test_three",
   338  								Status: moduletest.Error,
   339  							},
   340  						},
   341  					},
   342  				},
   343  			},
   344  			Expected: "\nFailure! 0 passed, 6 failed.\n",
   345  		},
   346  
   347  		"failed, errored, passed, and skipped tests": {
   348  			Suite: &moduletest.Suite{
   349  				Status: moduletest.Error,
   350  				Files: map[string]*moduletest.File{
   351  					"descriptive_test_name.tftest.hcl": {
   352  						Name:   "descriptive_test_name.tftest.hcl",
   353  						Status: moduletest.Fail,
   354  						Runs: []*moduletest.Run{
   355  							{
   356  								Name:   "test_one",
   357  								Status: moduletest.Pass,
   358  							},
   359  							{
   360  								Name:   "test_two",
   361  								Status: moduletest.Pass,
   362  							},
   363  							{
   364  								Name:   "test_three",
   365  								Status: moduletest.Fail,
   366  							},
   367  						},
   368  					},
   369  					"other_descriptive_test_name.tftest.hcl": {
   370  						Name:   "other_descriptive_test_name.tftest.hcl",
   371  						Status: moduletest.Error,
   372  						Runs: []*moduletest.Run{
   373  							{
   374  								Name:   "test_one",
   375  								Status: moduletest.Error,
   376  							},
   377  							{
   378  								Name:   "test_two",
   379  								Status: moduletest.Skip,
   380  							},
   381  							{
   382  								Name:   "test_three",
   383  								Status: moduletest.Skip,
   384  							},
   385  						},
   386  					},
   387  				},
   388  			},
   389  			Expected: "\nFailure! 2 passed, 2 failed, 2 skipped.\n",
   390  		},
   391  	}
   392  	for name, tc := range tcs {
   393  		t.Run(name, func(t *testing.T) {
   394  
   395  			streams, done := terminal.StreamsForTesting(t)
   396  			view := NewTest(arguments.ViewHuman, NewView(streams))
   397  
   398  			view.Conclusion(tc.Suite)
   399  
   400  			actual := done(t).Stdout()
   401  			expected := tc.Expected
   402  			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
   403  				t.Fatalf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
   404  			}
   405  		})
   406  	}
   407  }
   408  
   409  func TestTestHuman_File(t *testing.T) {
   410  	tcs := map[string]struct {
   411  		File     *moduletest.File
   412  		Expected string
   413  	}{
   414  		"pass": {
   415  			File:     &moduletest.File{Name: "main.tf", Status: moduletest.Pass},
   416  			Expected: "main.tf... pass\n",
   417  		},
   418  
   419  		"pending": {
   420  			File:     &moduletest.File{Name: "main.tf", Status: moduletest.Pending},
   421  			Expected: "main.tf... pending\n",
   422  		},
   423  
   424  		"skip": {
   425  			File:     &moduletest.File{Name: "main.tf", Status: moduletest.Skip},
   426  			Expected: "main.tf... skip\n",
   427  		},
   428  
   429  		"fail": {
   430  			File:     &moduletest.File{Name: "main.tf", Status: moduletest.Fail},
   431  			Expected: "main.tf... fail\n",
   432  		},
   433  
   434  		"error": {
   435  			File:     &moduletest.File{Name: "main.tf", Status: moduletest.Error},
   436  			Expected: "main.tf... fail\n",
   437  		},
   438  	}
   439  	for name, tc := range tcs {
   440  		t.Run(name, func(t *testing.T) {
   441  
   442  			streams, done := terminal.StreamsForTesting(t)
   443  			view := NewTest(arguments.ViewHuman, NewView(streams))
   444  
   445  			view.File(tc.File)
   446  
   447  			actual := done(t).Stdout()
   448  			expected := tc.Expected
   449  			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
   450  				t.Fatalf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
   451  			}
   452  		})
   453  	}
   454  }
   455  
   456  func TestTestHuman_Run(t *testing.T) {
   457  	tcs := map[string]struct {
   458  		Run    *moduletest.Run
   459  		StdOut string
   460  		StdErr string
   461  	}{
   462  		"pass": {
   463  			Run:    &moduletest.Run{Name: "run_block", Status: moduletest.Pass},
   464  			StdOut: "  run \"run_block\"... pass\n",
   465  		},
   466  
   467  		"pass_with_diags": {
   468  			Run: &moduletest.Run{
   469  				Name:        "run_block",
   470  				Status:      moduletest.Pass,
   471  				Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Warning, "a warning occurred", "some warning happened during this test")},
   472  			},
   473  			StdOut: `  run "run_block"... pass
   474  
   475  Warning: a warning occurred
   476  
   477  some warning happened during this test
   478  `,
   479  		},
   480  
   481  		"pending": {
   482  			Run:    &moduletest.Run{Name: "run_block", Status: moduletest.Pending},
   483  			StdOut: "  run \"run_block\"... pending\n",
   484  		},
   485  
   486  		"skip": {
   487  			Run:    &moduletest.Run{Name: "run_block", Status: moduletest.Skip},
   488  			StdOut: "  run \"run_block\"... skip\n",
   489  		},
   490  
   491  		"fail": {
   492  			Run:    &moduletest.Run{Name: "run_block", Status: moduletest.Fail},
   493  			StdOut: "  run \"run_block\"... fail\n",
   494  		},
   495  
   496  		"fail_with_diags": {
   497  			Run: &moduletest.Run{
   498  				Name:   "run_block",
   499  				Status: moduletest.Fail,
   500  				Diagnostics: tfdiags.Diagnostics{
   501  					tfdiags.Sourceless(tfdiags.Error, "a comparison failed", "details details details"),
   502  					tfdiags.Sourceless(tfdiags.Error, "a second comparison failed", "other details"),
   503  				},
   504  			},
   505  			StdOut: "  run \"run_block\"... fail\n",
   506  			StdErr: `
   507  Error: a comparison failed
   508  
   509  details details details
   510  
   511  Error: a second comparison failed
   512  
   513  other details
   514  `,
   515  		},
   516  
   517  		"error": {
   518  			Run:    &moduletest.Run{Name: "run_block", Status: moduletest.Error},
   519  			StdOut: "  run \"run_block\"... fail\n",
   520  		},
   521  
   522  		"error_with_diags": {
   523  			Run: &moduletest.Run{
   524  				Name:        "run_block",
   525  				Status:      moduletest.Error,
   526  				Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Error, "an error occurred", "something bad happened during this test")},
   527  			},
   528  			StdOut: "  run \"run_block\"... fail\n",
   529  			StdErr: `
   530  Error: an error occurred
   531  
   532  something bad happened during this test
   533  `,
   534  		},
   535  		"verbose_plan": {
   536  			Run: &moduletest.Run{
   537  				Name:   "run_block",
   538  				Status: moduletest.Pass,
   539  				Config: &configs.TestRun{
   540  					Command: configs.PlanTestCommand,
   541  				},
   542  				Verbose: &moduletest.Verbose{
   543  					Plan: &plans.Plan{
   544  						Changes: &plans.Changes{
   545  							Resources: []*plans.ResourceInstanceChangeSrc{
   546  								{
   547  									Addr: addrs.AbsResourceInstance{
   548  										Module: addrs.RootModuleInstance,
   549  										Resource: addrs.ResourceInstance{
   550  											Resource: addrs.Resource{
   551  												Mode: addrs.ManagedResourceMode,
   552  												Type: "test_resource",
   553  												Name: "creating",
   554  											},
   555  										},
   556  									},
   557  									PrevRunAddr: addrs.AbsResourceInstance{
   558  										Module: addrs.RootModuleInstance,
   559  										Resource: addrs.ResourceInstance{
   560  											Resource: addrs.Resource{
   561  												Mode: addrs.ManagedResourceMode,
   562  												Type: "test_resource",
   563  												Name: "creating",
   564  											},
   565  										},
   566  									},
   567  									ProviderAddr: addrs.AbsProviderConfig{
   568  										Module: addrs.RootModule,
   569  										Provider: addrs.Provider{
   570  											Hostname:  addrs.DefaultProviderRegistryHost,
   571  											Namespace: "hashicorp",
   572  											Type:      "test",
   573  										},
   574  									},
   575  									ChangeSrc: plans.ChangeSrc{
   576  										Action: plans.Create,
   577  										After: dynamicValue(
   578  											t,
   579  											cty.ObjectVal(map[string]cty.Value{
   580  												"value": cty.StringVal("Hello, world!"),
   581  											}),
   582  											cty.Object(map[string]cty.Type{
   583  												"value": cty.String,
   584  											})),
   585  									},
   586  								},
   587  							},
   588  						},
   589  					},
   590  					State:  states.NewState(), // empty state
   591  					Config: &configs.Config{},
   592  					Providers: map[addrs.Provider]providers.ProviderSchema{
   593  						addrs.Provider{
   594  							Hostname:  addrs.DefaultProviderRegistryHost,
   595  							Namespace: "hashicorp",
   596  							Type:      "test",
   597  						}: {
   598  							ResourceTypes: map[string]providers.Schema{
   599  								"test_resource": {
   600  									Block: &configschema.Block{
   601  										Attributes: map[string]*configschema.Attribute{
   602  											"value": {
   603  												Type: cty.String,
   604  											},
   605  										},
   606  									},
   607  								},
   608  							},
   609  						},
   610  					},
   611  				},
   612  			},
   613  			StdOut: `  run "run_block"... pass
   614  
   615  Terraform used the selected providers to generate the following execution
   616  plan. Resource actions are indicated with the following symbols:
   617    + create
   618  
   619  Terraform will perform the following actions:
   620  
   621    # test_resource.creating will be created
   622    + resource "test_resource" "creating" {
   623        + value = "Hello, world!"
   624      }
   625  
   626  Plan: 1 to add, 0 to change, 0 to destroy.
   627  `,
   628  		},
   629  		"verbose_apply": {
   630  			Run: &moduletest.Run{
   631  				Name:   "run_block",
   632  				Status: moduletest.Pass,
   633  				Config: &configs.TestRun{
   634  					Command: configs.ApplyTestCommand,
   635  				},
   636  				Verbose: &moduletest.Verbose{
   637  					Plan: &plans.Plan{}, // empty plan
   638  					State: states.BuildState(func(state *states.SyncState) {
   639  						state.SetResourceInstanceCurrent(
   640  							addrs.AbsResourceInstance{
   641  								Module: addrs.RootModuleInstance,
   642  								Resource: addrs.ResourceInstance{
   643  									Resource: addrs.Resource{
   644  										Mode: addrs.ManagedResourceMode,
   645  										Type: "test_resource",
   646  										Name: "creating",
   647  									},
   648  								},
   649  							},
   650  							&states.ResourceInstanceObjectSrc{
   651  								AttrsJSON: []byte(`{"value":"foobar"}`),
   652  							},
   653  							addrs.AbsProviderConfig{
   654  								Module: addrs.RootModule,
   655  								Provider: addrs.Provider{
   656  									Hostname:  addrs.DefaultProviderRegistryHost,
   657  									Namespace: "hashicorp",
   658  									Type:      "test",
   659  								},
   660  							})
   661  					}),
   662  					Config: &configs.Config{},
   663  					Providers: map[addrs.Provider]providers.ProviderSchema{
   664  						addrs.Provider{
   665  							Hostname:  addrs.DefaultProviderRegistryHost,
   666  							Namespace: "hashicorp",
   667  							Type:      "test",
   668  						}: {
   669  							ResourceTypes: map[string]providers.Schema{
   670  								"test_resource": {
   671  									Block: &configschema.Block{
   672  										Attributes: map[string]*configschema.Attribute{
   673  											"value": {
   674  												Type: cty.String,
   675  											},
   676  										},
   677  									},
   678  								},
   679  							},
   680  						},
   681  					},
   682  				},
   683  			},
   684  			StdOut: `  run "run_block"... pass
   685  # test_resource.creating:
   686  resource "test_resource" "creating" {
   687      value = "foobar"
   688  }
   689  `,
   690  		},
   691  	}
   692  	for name, tc := range tcs {
   693  		t.Run(name, func(t *testing.T) {
   694  			file := &moduletest.File{
   695  				Name: "main.tftest.hcl",
   696  			}
   697  
   698  			streams, done := terminal.StreamsForTesting(t)
   699  			view := NewTest(arguments.ViewHuman, NewView(streams))
   700  
   701  			view.Run(tc.Run, file)
   702  
   703  			output := done(t)
   704  			actual, expected := output.Stdout(), tc.StdOut
   705  			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
   706  				t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
   707  			}
   708  
   709  			actual, expected = output.Stderr(), tc.StdErr
   710  			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
   711  				t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
   712  			}
   713  		})
   714  	}
   715  }
   716  
   717  func TestTestHuman_DestroySummary(t *testing.T) {
   718  	tcs := map[string]struct {
   719  		diags  tfdiags.Diagnostics
   720  		run    *moduletest.Run
   721  		file   *moduletest.File
   722  		state  *states.State
   723  		stdout string
   724  		stderr string
   725  	}{
   726  		"empty": {
   727  			diags: nil,
   728  			file:  &moduletest.File{Name: "main.tftest.hcl"},
   729  			state: states.NewState(),
   730  		},
   731  		"empty_state_only_warnings": {
   732  			diags: tfdiags.Diagnostics{
   733  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "some thing not very bad happened"),
   734  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "some thing not very bad happened again"),
   735  			},
   736  			file:  &moduletest.File{Name: "main.tftest.hcl"},
   737  			state: states.NewState(),
   738  			stdout: `
   739  Warning: first warning
   740  
   741  some thing not very bad happened
   742  
   743  Warning: second warning
   744  
   745  some thing not very bad happened again
   746  `,
   747  		},
   748  		"empty_state_with_errors": {
   749  			diags: tfdiags.Diagnostics{
   750  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "some thing not very bad happened"),
   751  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "some thing not very bad happened again"),
   752  				tfdiags.Sourceless(tfdiags.Error, "first error", "this time it is very bad"),
   753  			},
   754  			file:  &moduletest.File{Name: "main.tftest.hcl"},
   755  			state: states.NewState(),
   756  			stdout: `
   757  Warning: first warning
   758  
   759  some thing not very bad happened
   760  
   761  Warning: second warning
   762  
   763  some thing not very bad happened again
   764  `,
   765  			stderr: `Terraform encountered an error destroying resources created while executing
   766  main.tftest.hcl.
   767  
   768  Error: first error
   769  
   770  this time it is very bad
   771  `,
   772  		},
   773  		"error_from_run": {
   774  			diags: tfdiags.Diagnostics{
   775  				tfdiags.Sourceless(tfdiags.Error, "first error", "this time it is very bad"),
   776  			},
   777  			run:   &moduletest.Run{Name: "run_block"},
   778  			file:  &moduletest.File{Name: "main.tftest.hcl"},
   779  			state: states.NewState(),
   780  			stderr: `Terraform encountered an error destroying resources created while executing
   781  main.tftest.hcl/run_block.
   782  
   783  Error: first error
   784  
   785  this time it is very bad
   786  `,
   787  		},
   788  		"state_only_warnings": {
   789  			diags: tfdiags.Diagnostics{
   790  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "some thing not very bad happened"),
   791  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "some thing not very bad happened again"),
   792  			},
   793  			file: &moduletest.File{Name: "main.tftest.hcl"},
   794  			state: states.BuildState(func(state *states.SyncState) {
   795  				state.SetResourceInstanceCurrent(
   796  					addrs.Resource{
   797  						Mode: addrs.ManagedResourceMode,
   798  						Type: "test",
   799  						Name: "foo",
   800  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   801  					&states.ResourceInstanceObjectSrc{
   802  						Status: states.ObjectReady,
   803  					},
   804  					addrs.AbsProviderConfig{
   805  						Module:   addrs.RootModule,
   806  						Provider: addrs.NewDefaultProvider("test"),
   807  					})
   808  				state.SetResourceInstanceCurrent(
   809  					addrs.Resource{
   810  						Mode: addrs.ManagedResourceMode,
   811  						Type: "test",
   812  						Name: "bar",
   813  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   814  					&states.ResourceInstanceObjectSrc{
   815  						Status: states.ObjectReady,
   816  					},
   817  					addrs.AbsProviderConfig{
   818  						Module:   addrs.RootModule,
   819  						Provider: addrs.NewDefaultProvider("test"),
   820  					})
   821  				state.SetResourceInstanceDeposed(
   822  					addrs.Resource{
   823  						Mode: addrs.ManagedResourceMode,
   824  						Type: "test",
   825  						Name: "bar",
   826  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   827  					"0fcb640a",
   828  					&states.ResourceInstanceObjectSrc{
   829  						Status: states.ObjectReady,
   830  					},
   831  					addrs.AbsProviderConfig{
   832  						Module:   addrs.RootModule,
   833  						Provider: addrs.NewDefaultProvider("test"),
   834  					})
   835  			}),
   836  			stdout: `
   837  Warning: first warning
   838  
   839  some thing not very bad happened
   840  
   841  Warning: second warning
   842  
   843  some thing not very bad happened again
   844  `,
   845  			stderr: `
   846  Terraform left the following resources in state after executing
   847  main.tftest.hcl, and they need to be cleaned up manually:
   848    - test.bar
   849    - test.bar (0fcb640a)
   850    - test.foo
   851  `,
   852  		},
   853  		"state_with_errors": {
   854  			diags: tfdiags.Diagnostics{
   855  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "some thing not very bad happened"),
   856  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "some thing not very bad happened again"),
   857  				tfdiags.Sourceless(tfdiags.Error, "first error", "this time it is very bad"),
   858  			},
   859  			file: &moduletest.File{Name: "main.tftest.hcl"},
   860  			state: states.BuildState(func(state *states.SyncState) {
   861  				state.SetResourceInstanceCurrent(
   862  					addrs.Resource{
   863  						Mode: addrs.ManagedResourceMode,
   864  						Type: "test",
   865  						Name: "foo",
   866  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   867  					&states.ResourceInstanceObjectSrc{
   868  						Status: states.ObjectReady,
   869  					},
   870  					addrs.AbsProviderConfig{
   871  						Module:   addrs.RootModule,
   872  						Provider: addrs.NewDefaultProvider("test"),
   873  					})
   874  				state.SetResourceInstanceCurrent(
   875  					addrs.Resource{
   876  						Mode: addrs.ManagedResourceMode,
   877  						Type: "test",
   878  						Name: "bar",
   879  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   880  					&states.ResourceInstanceObjectSrc{
   881  						Status: states.ObjectReady,
   882  					},
   883  					addrs.AbsProviderConfig{
   884  						Module:   addrs.RootModule,
   885  						Provider: addrs.NewDefaultProvider("test"),
   886  					})
   887  				state.SetResourceInstanceDeposed(
   888  					addrs.Resource{
   889  						Mode: addrs.ManagedResourceMode,
   890  						Type: "test",
   891  						Name: "bar",
   892  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   893  					"0fcb640a",
   894  					&states.ResourceInstanceObjectSrc{
   895  						Status: states.ObjectReady,
   896  					},
   897  					addrs.AbsProviderConfig{
   898  						Module:   addrs.RootModule,
   899  						Provider: addrs.NewDefaultProvider("test"),
   900  					})
   901  			}),
   902  			stdout: `
   903  Warning: first warning
   904  
   905  some thing not very bad happened
   906  
   907  Warning: second warning
   908  
   909  some thing not very bad happened again
   910  `,
   911  			stderr: `Terraform encountered an error destroying resources created while executing
   912  main.tftest.hcl.
   913  
   914  Error: first error
   915  
   916  this time it is very bad
   917  
   918  Terraform left the following resources in state after executing
   919  main.tftest.hcl, and they need to be cleaned up manually:
   920    - test.bar
   921    - test.bar (0fcb640a)
   922    - test.foo
   923  `,
   924  		},
   925  	}
   926  	for name, tc := range tcs {
   927  		t.Run(name, func(t *testing.T) {
   928  			streams, done := terminal.StreamsForTesting(t)
   929  			view := NewTest(arguments.ViewHuman, NewView(streams))
   930  
   931  			view.DestroySummary(tc.diags, tc.run, tc.file, tc.state)
   932  
   933  			output := done(t)
   934  			actual, expected := output.Stdout(), tc.stdout
   935  			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
   936  				t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
   937  			}
   938  
   939  			actual, expected = output.Stderr(), tc.stderr
   940  			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
   941  				t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
   942  			}
   943  		})
   944  	}
   945  }
   946  
   947  func TestTestHuman_FatalInterruptSummary(t *testing.T) {
   948  	tcs := map[string]struct {
   949  		states  map[*moduletest.Run]*states.State
   950  		run     *moduletest.Run
   951  		created []*plans.ResourceInstanceChangeSrc
   952  		want    string
   953  	}{
   954  		"no_state_only_plan": {
   955  			states: make(map[*moduletest.Run]*states.State),
   956  			run: &moduletest.Run{
   957  				Config: &configs.TestRun{},
   958  				Name:   "run_block",
   959  			},
   960  			created: []*plans.ResourceInstanceChangeSrc{
   961  				{
   962  					Addr: addrs.AbsResourceInstance{
   963  						Module: addrs.RootModuleInstance,
   964  						Resource: addrs.ResourceInstance{
   965  							Resource: addrs.Resource{
   966  								Mode: addrs.ManagedResourceMode,
   967  								Type: "test_instance",
   968  								Name: "one",
   969  							},
   970  						},
   971  					},
   972  					ChangeSrc: plans.ChangeSrc{
   973  						Action: plans.Create,
   974  					},
   975  				},
   976  				{
   977  					Addr: addrs.AbsResourceInstance{
   978  						Module: addrs.RootModuleInstance,
   979  						Resource: addrs.ResourceInstance{
   980  							Resource: addrs.Resource{
   981  								Mode: addrs.ManagedResourceMode,
   982  								Type: "test_instance",
   983  								Name: "two",
   984  							},
   985  						},
   986  					},
   987  					ChangeSrc: plans.ChangeSrc{
   988  						Action: plans.Create,
   989  					},
   990  				},
   991  			},
   992  			want: `
   993  Terraform was interrupted while executing main.tftest.hcl, and may not have
   994  performed the expected cleanup operations.
   995  
   996  Terraform was in the process of creating the following resources for
   997  "run_block" from the module under test, and they may not have been destroyed:
   998    - test_instance.one
   999    - test_instance.two
  1000  `,
  1001  		},
  1002  		"file_state_no_plan": {
  1003  			states: map[*moduletest.Run]*states.State{
  1004  				nil: states.BuildState(func(state *states.SyncState) {
  1005  					state.SetResourceInstanceCurrent(
  1006  						addrs.AbsResourceInstance{
  1007  							Module: addrs.RootModuleInstance,
  1008  							Resource: addrs.ResourceInstance{
  1009  								Resource: addrs.Resource{
  1010  									Mode: addrs.ManagedResourceMode,
  1011  									Type: "test_instance",
  1012  									Name: "one",
  1013  								},
  1014  							},
  1015  						},
  1016  						&states.ResourceInstanceObjectSrc{},
  1017  						addrs.AbsProviderConfig{})
  1018  
  1019  					state.SetResourceInstanceCurrent(
  1020  						addrs.AbsResourceInstance{
  1021  							Module: addrs.RootModuleInstance,
  1022  							Resource: addrs.ResourceInstance{
  1023  								Resource: addrs.Resource{
  1024  									Mode: addrs.ManagedResourceMode,
  1025  									Type: "test_instance",
  1026  									Name: "two",
  1027  								},
  1028  							},
  1029  						},
  1030  						&states.ResourceInstanceObjectSrc{},
  1031  						addrs.AbsProviderConfig{})
  1032  				}),
  1033  			},
  1034  			created: nil,
  1035  			want: `
  1036  Terraform was interrupted while executing main.tftest.hcl, and may not have
  1037  performed the expected cleanup operations.
  1038  
  1039  Terraform has already created the following resources from the module under
  1040  test:
  1041    - test_instance.one
  1042    - test_instance.two
  1043  `,
  1044  		},
  1045  		"run_states_no_plan": {
  1046  			states: map[*moduletest.Run]*states.State{
  1047  				&moduletest.Run{
  1048  					Name: "setup_block",
  1049  					Config: &configs.TestRun{
  1050  						Module: &configs.TestRunModuleCall{
  1051  							Source: addrs.ModuleSourceLocal("../setup"),
  1052  						},
  1053  					},
  1054  				}: states.BuildState(func(state *states.SyncState) {
  1055  					state.SetResourceInstanceCurrent(
  1056  						addrs.AbsResourceInstance{
  1057  							Module: addrs.RootModuleInstance,
  1058  							Resource: addrs.ResourceInstance{
  1059  								Resource: addrs.Resource{
  1060  									Mode: addrs.ManagedResourceMode,
  1061  									Type: "test_instance",
  1062  									Name: "one",
  1063  								},
  1064  							},
  1065  						},
  1066  						&states.ResourceInstanceObjectSrc{},
  1067  						addrs.AbsProviderConfig{})
  1068  
  1069  					state.SetResourceInstanceCurrent(
  1070  						addrs.AbsResourceInstance{
  1071  							Module: addrs.RootModuleInstance,
  1072  							Resource: addrs.ResourceInstance{
  1073  								Resource: addrs.Resource{
  1074  									Mode: addrs.ManagedResourceMode,
  1075  									Type: "test_instance",
  1076  									Name: "two",
  1077  								},
  1078  							},
  1079  						},
  1080  						&states.ResourceInstanceObjectSrc{},
  1081  						addrs.AbsProviderConfig{})
  1082  				}),
  1083  			},
  1084  			created: nil,
  1085  			want: `
  1086  Terraform was interrupted while executing main.tftest.hcl, and may not have
  1087  performed the expected cleanup operations.
  1088  
  1089  Terraform has already created the following resources for "setup_block" from
  1090  "../setup":
  1091    - test_instance.one
  1092    - test_instance.two
  1093  `,
  1094  		},
  1095  		"all_states_with_plan": {
  1096  			states: map[*moduletest.Run]*states.State{
  1097  				&moduletest.Run{
  1098  					Name: "setup_block",
  1099  					Config: &configs.TestRun{
  1100  						Module: &configs.TestRunModuleCall{
  1101  							Source: addrs.ModuleSourceLocal("../setup"),
  1102  						},
  1103  					},
  1104  				}: states.BuildState(func(state *states.SyncState) {
  1105  					state.SetResourceInstanceCurrent(
  1106  						addrs.AbsResourceInstance{
  1107  							Module: addrs.RootModuleInstance,
  1108  							Resource: addrs.ResourceInstance{
  1109  								Resource: addrs.Resource{
  1110  									Mode: addrs.ManagedResourceMode,
  1111  									Type: "test_instance",
  1112  									Name: "setup_one",
  1113  								},
  1114  							},
  1115  						},
  1116  						&states.ResourceInstanceObjectSrc{},
  1117  						addrs.AbsProviderConfig{})
  1118  
  1119  					state.SetResourceInstanceCurrent(
  1120  						addrs.AbsResourceInstance{
  1121  							Module: addrs.RootModuleInstance,
  1122  							Resource: addrs.ResourceInstance{
  1123  								Resource: addrs.Resource{
  1124  									Mode: addrs.ManagedResourceMode,
  1125  									Type: "test_instance",
  1126  									Name: "setup_two",
  1127  								},
  1128  							},
  1129  						},
  1130  						&states.ResourceInstanceObjectSrc{},
  1131  						addrs.AbsProviderConfig{})
  1132  				}),
  1133  				nil: states.BuildState(func(state *states.SyncState) {
  1134  					state.SetResourceInstanceCurrent(
  1135  						addrs.AbsResourceInstance{
  1136  							Module: addrs.RootModuleInstance,
  1137  							Resource: addrs.ResourceInstance{
  1138  								Resource: addrs.Resource{
  1139  									Mode: addrs.ManagedResourceMode,
  1140  									Type: "test_instance",
  1141  									Name: "one",
  1142  								},
  1143  							},
  1144  						},
  1145  						&states.ResourceInstanceObjectSrc{},
  1146  						addrs.AbsProviderConfig{})
  1147  
  1148  					state.SetResourceInstanceCurrent(
  1149  						addrs.AbsResourceInstance{
  1150  							Module: addrs.RootModuleInstance,
  1151  							Resource: addrs.ResourceInstance{
  1152  								Resource: addrs.Resource{
  1153  									Mode: addrs.ManagedResourceMode,
  1154  									Type: "test_instance",
  1155  									Name: "two",
  1156  								},
  1157  							},
  1158  						},
  1159  						&states.ResourceInstanceObjectSrc{},
  1160  						addrs.AbsProviderConfig{})
  1161  				}),
  1162  			},
  1163  			created: []*plans.ResourceInstanceChangeSrc{
  1164  				{
  1165  					Addr: addrs.AbsResourceInstance{
  1166  						Module: addrs.RootModuleInstance,
  1167  						Resource: addrs.ResourceInstance{
  1168  							Resource: addrs.Resource{
  1169  								Mode: addrs.ManagedResourceMode,
  1170  								Type: "test_instance",
  1171  								Name: "new_one",
  1172  							},
  1173  						},
  1174  					},
  1175  					ChangeSrc: plans.ChangeSrc{
  1176  						Action: plans.Create,
  1177  					},
  1178  				},
  1179  				{
  1180  					Addr: addrs.AbsResourceInstance{
  1181  						Module: addrs.RootModuleInstance,
  1182  						Resource: addrs.ResourceInstance{
  1183  							Resource: addrs.Resource{
  1184  								Mode: addrs.ManagedResourceMode,
  1185  								Type: "test_instance",
  1186  								Name: "new_two",
  1187  							},
  1188  						},
  1189  					},
  1190  					ChangeSrc: plans.ChangeSrc{
  1191  						Action: plans.Create,
  1192  					},
  1193  				},
  1194  			},
  1195  			run: &moduletest.Run{
  1196  				Config: &configs.TestRun{},
  1197  				Name:   "run_block",
  1198  			},
  1199  			want: `
  1200  Terraform was interrupted while executing main.tftest.hcl, and may not have
  1201  performed the expected cleanup operations.
  1202  
  1203  Terraform has already created the following resources from the module under
  1204  test:
  1205    - test_instance.one
  1206    - test_instance.two
  1207  
  1208  Terraform has already created the following resources for "setup_block" from
  1209  "../setup":
  1210    - test_instance.setup_one
  1211    - test_instance.setup_two
  1212  
  1213  Terraform was in the process of creating the following resources for
  1214  "run_block" from the module under test, and they may not have been destroyed:
  1215    - test_instance.new_one
  1216    - test_instance.new_two
  1217  `,
  1218  		},
  1219  	}
  1220  	for name, tc := range tcs {
  1221  		t.Run(name, func(t *testing.T) {
  1222  			streams, done := terminal.StreamsForTesting(t)
  1223  			view := NewTest(arguments.ViewHuman, NewView(streams))
  1224  
  1225  			file := &moduletest.File{
  1226  				Name: "main.tftest.hcl",
  1227  				Runs: func() []*moduletest.Run {
  1228  					var runs []*moduletest.Run
  1229  					for run := range tc.states {
  1230  						if run != nil {
  1231  							runs = append(runs, run)
  1232  						}
  1233  					}
  1234  					return runs
  1235  				}(),
  1236  			}
  1237  
  1238  			view.FatalInterruptSummary(tc.run, file, tc.states, tc.created)
  1239  			actual, expected := done(t).Stderr(), tc.want
  1240  			if diff := cmp.Diff(expected, actual); len(diff) > 0 {
  1241  				t.Errorf("expected:\n%s\nactual:\n%s\ndiff:\n%s", expected, actual, diff)
  1242  			}
  1243  		})
  1244  	}
  1245  }
  1246  
  1247  func TestTestJSON_Abstract(t *testing.T) {
  1248  	tcs := map[string]struct {
  1249  		suite *moduletest.Suite
  1250  		want  []map[string]interface{}
  1251  	}{
  1252  		"single": {
  1253  			suite: &moduletest.Suite{
  1254  				Files: map[string]*moduletest.File{
  1255  					"main.tftest.hcl": {
  1256  						Runs: []*moduletest.Run{
  1257  							{
  1258  								Name: "setup",
  1259  							},
  1260  						},
  1261  					},
  1262  				},
  1263  			},
  1264  			want: []map[string]interface{}{
  1265  				{
  1266  					"@level":   "info",
  1267  					"@message": "Found 1 file and 1 run block",
  1268  					"@module":  "terraform.ui",
  1269  					"test_abstract": map[string]interface{}{
  1270  						"main.tftest.hcl": []interface{}{
  1271  							"setup",
  1272  						},
  1273  					},
  1274  					"type": "test_abstract",
  1275  				},
  1276  			},
  1277  		},
  1278  		"plural": {
  1279  			suite: &moduletest.Suite{
  1280  				Files: map[string]*moduletest.File{
  1281  					"main.tftest.hcl": {
  1282  						Runs: []*moduletest.Run{
  1283  							{
  1284  								Name: "setup",
  1285  							},
  1286  							{
  1287  								Name: "test",
  1288  							},
  1289  						},
  1290  					},
  1291  					"other.tftest.hcl": {
  1292  						Runs: []*moduletest.Run{
  1293  							{
  1294  								Name: "test",
  1295  							},
  1296  						},
  1297  					},
  1298  				},
  1299  			},
  1300  			want: []map[string]interface{}{
  1301  				{
  1302  					"@level":   "info",
  1303  					"@message": "Found 2 files and 3 run blocks",
  1304  					"@module":  "terraform.ui",
  1305  					"test_abstract": map[string]interface{}{
  1306  						"main.tftest.hcl": []interface{}{
  1307  							"setup",
  1308  							"test",
  1309  						},
  1310  						"other.tftest.hcl": []interface{}{
  1311  							"test",
  1312  						},
  1313  					},
  1314  					"type": "test_abstract",
  1315  				},
  1316  			},
  1317  		},
  1318  	}
  1319  	for name, tc := range tcs {
  1320  		t.Run(name, func(t *testing.T) {
  1321  			streams, done := terminal.StreamsForTesting(t)
  1322  			view := NewTest(arguments.ViewJSON, NewView(streams))
  1323  
  1324  			view.Abstract(tc.suite)
  1325  			testJSONViewOutputEquals(t, done(t).All(), tc.want)
  1326  		})
  1327  	}
  1328  }
  1329  
  1330  func TestTestJSON_Conclusion(t *testing.T) {
  1331  	tcs := map[string]struct {
  1332  		suite *moduletest.Suite
  1333  		want  []map[string]interface{}
  1334  	}{
  1335  		"no tests": {
  1336  			suite: &moduletest.Suite{},
  1337  			want: []map[string]interface{}{
  1338  				{
  1339  					"@level":   "info",
  1340  					"@message": "Executed 0 tests.",
  1341  					"@module":  "terraform.ui",
  1342  					"test_summary": map[string]interface{}{
  1343  						"status":  "pending",
  1344  						"errored": 0.0,
  1345  						"failed":  0.0,
  1346  						"passed":  0.0,
  1347  						"skipped": 0.0,
  1348  					},
  1349  					"type": "test_summary",
  1350  				},
  1351  			},
  1352  		},
  1353  
  1354  		"only skipped tests": {
  1355  			suite: &moduletest.Suite{
  1356  				Status: moduletest.Skip,
  1357  				Files: map[string]*moduletest.File{
  1358  					"descriptive_test_name.tftest.hcl": {
  1359  						Name:   "descriptive_test_name.tftest.hcl",
  1360  						Status: moduletest.Skip,
  1361  						Runs: []*moduletest.Run{
  1362  							{
  1363  								Name:   "test_one",
  1364  								Status: moduletest.Skip,
  1365  							},
  1366  							{
  1367  								Name:   "test_two",
  1368  								Status: moduletest.Skip,
  1369  							},
  1370  							{
  1371  								Name:   "test_three",
  1372  								Status: moduletest.Skip,
  1373  							},
  1374  						},
  1375  					},
  1376  					"other_descriptive_test_name.tftest.hcl": {
  1377  						Name:   "other_descriptive_test_name.tftest.hcl",
  1378  						Status: moduletest.Skip,
  1379  						Runs: []*moduletest.Run{
  1380  							{
  1381  								Name:   "test_one",
  1382  								Status: moduletest.Skip,
  1383  							},
  1384  							{
  1385  								Name:   "test_two",
  1386  								Status: moduletest.Skip,
  1387  							},
  1388  							{
  1389  								Name:   "test_three",
  1390  								Status: moduletest.Skip,
  1391  							},
  1392  						},
  1393  					},
  1394  				},
  1395  			},
  1396  			want: []map[string]interface{}{
  1397  				{
  1398  					"@level":   "info",
  1399  					"@message": "Executed 0 tests, 6 skipped.",
  1400  					"@module":  "terraform.ui",
  1401  					"test_summary": map[string]interface{}{
  1402  						"status":  "skip",
  1403  						"errored": 0.0,
  1404  						"failed":  0.0,
  1405  						"passed":  0.0,
  1406  						"skipped": 6.0,
  1407  					},
  1408  					"type": "test_summary",
  1409  				},
  1410  			},
  1411  		},
  1412  
  1413  		"only passed tests": {
  1414  			suite: &moduletest.Suite{
  1415  				Status: moduletest.Pass,
  1416  				Files: map[string]*moduletest.File{
  1417  					"descriptive_test_name.tftest.hcl": {
  1418  						Name:   "descriptive_test_name.tftest.hcl",
  1419  						Status: moduletest.Pass,
  1420  						Runs: []*moduletest.Run{
  1421  							{
  1422  								Name:   "test_one",
  1423  								Status: moduletest.Pass,
  1424  							},
  1425  							{
  1426  								Name:   "test_two",
  1427  								Status: moduletest.Pass,
  1428  							},
  1429  							{
  1430  								Name:   "test_three",
  1431  								Status: moduletest.Pass,
  1432  							},
  1433  						},
  1434  					},
  1435  					"other_descriptive_test_name.tftest.hcl": {
  1436  						Name:   "other_descriptive_test_name.tftest.hcl",
  1437  						Status: moduletest.Pass,
  1438  						Runs: []*moduletest.Run{
  1439  							{
  1440  								Name:   "test_one",
  1441  								Status: moduletest.Pass,
  1442  							},
  1443  							{
  1444  								Name:   "test_two",
  1445  								Status: moduletest.Pass,
  1446  							},
  1447  							{
  1448  								Name:   "test_three",
  1449  								Status: moduletest.Pass,
  1450  							},
  1451  						},
  1452  					},
  1453  				},
  1454  			},
  1455  			want: []map[string]interface{}{
  1456  				{
  1457  					"@level":   "info",
  1458  					"@message": "Success! 6 passed, 0 failed.",
  1459  					"@module":  "terraform.ui",
  1460  					"test_summary": map[string]interface{}{
  1461  						"status":  "pass",
  1462  						"errored": 0.0,
  1463  						"failed":  0.0,
  1464  						"passed":  6.0,
  1465  						"skipped": 0.0,
  1466  					},
  1467  					"type": "test_summary",
  1468  				},
  1469  			},
  1470  		},
  1471  
  1472  		"passed and skipped tests": {
  1473  			suite: &moduletest.Suite{
  1474  				Status: moduletest.Pass,
  1475  				Files: map[string]*moduletest.File{
  1476  					"descriptive_test_name.tftest.hcl": {
  1477  						Name:   "descriptive_test_name.tftest.hcl",
  1478  						Status: moduletest.Pass,
  1479  						Runs: []*moduletest.Run{
  1480  							{
  1481  								Name:   "test_one",
  1482  								Status: moduletest.Pass,
  1483  							},
  1484  							{
  1485  								Name:   "test_two",
  1486  								Status: moduletest.Skip,
  1487  							},
  1488  							{
  1489  								Name:   "test_three",
  1490  								Status: moduletest.Pass,
  1491  							},
  1492  						},
  1493  					},
  1494  					"other_descriptive_test_name.tftest.hcl": {
  1495  						Name:   "other_descriptive_test_name.tftest.hcl",
  1496  						Status: moduletest.Pass,
  1497  						Runs: []*moduletest.Run{
  1498  							{
  1499  								Name:   "test_one",
  1500  								Status: moduletest.Skip,
  1501  							},
  1502  							{
  1503  								Name:   "test_two",
  1504  								Status: moduletest.Pass,
  1505  							},
  1506  							{
  1507  								Name:   "test_three",
  1508  								Status: moduletest.Pass,
  1509  							},
  1510  						},
  1511  					},
  1512  				},
  1513  			},
  1514  			want: []map[string]interface{}{
  1515  				{
  1516  					"@level":   "info",
  1517  					"@message": "Success! 4 passed, 0 failed, 2 skipped.",
  1518  					"@module":  "terraform.ui",
  1519  					"test_summary": map[string]interface{}{
  1520  						"status":  "pass",
  1521  						"errored": 0.0,
  1522  						"failed":  0.0,
  1523  						"passed":  4.0,
  1524  						"skipped": 2.0,
  1525  					},
  1526  					"type": "test_summary",
  1527  				},
  1528  			},
  1529  		},
  1530  
  1531  		"only failed tests": {
  1532  			suite: &moduletest.Suite{
  1533  				Status: moduletest.Fail,
  1534  				Files: map[string]*moduletest.File{
  1535  					"descriptive_test_name.tftest.hcl": {
  1536  						Name:   "descriptive_test_name.tftest.hcl",
  1537  						Status: moduletest.Fail,
  1538  						Runs: []*moduletest.Run{
  1539  							{
  1540  								Name:   "test_one",
  1541  								Status: moduletest.Fail,
  1542  							},
  1543  							{
  1544  								Name:   "test_two",
  1545  								Status: moduletest.Fail,
  1546  							},
  1547  							{
  1548  								Name:   "test_three",
  1549  								Status: moduletest.Fail,
  1550  							},
  1551  						},
  1552  					},
  1553  					"other_descriptive_test_name.tftest.hcl": {
  1554  						Name:   "other_descriptive_test_name.tftest.hcl",
  1555  						Status: moduletest.Fail,
  1556  						Runs: []*moduletest.Run{
  1557  							{
  1558  								Name:   "test_one",
  1559  								Status: moduletest.Fail,
  1560  							},
  1561  							{
  1562  								Name:   "test_two",
  1563  								Status: moduletest.Fail,
  1564  							},
  1565  							{
  1566  								Name:   "test_three",
  1567  								Status: moduletest.Fail,
  1568  							},
  1569  						},
  1570  					},
  1571  				},
  1572  			},
  1573  			want: []map[string]interface{}{
  1574  				{
  1575  					"@level":   "info",
  1576  					"@message": "Failure! 0 passed, 6 failed.",
  1577  					"@module":  "terraform.ui",
  1578  					"test_summary": map[string]interface{}{
  1579  						"status":  "fail",
  1580  						"errored": 0.0,
  1581  						"failed":  6.0,
  1582  						"passed":  0.0,
  1583  						"skipped": 0.0,
  1584  					},
  1585  					"type": "test_summary",
  1586  				},
  1587  			},
  1588  		},
  1589  
  1590  		"failed and skipped tests": {
  1591  			suite: &moduletest.Suite{
  1592  				Status: moduletest.Fail,
  1593  				Files: map[string]*moduletest.File{
  1594  					"descriptive_test_name.tftest.hcl": {
  1595  						Name:   "descriptive_test_name.tftest.hcl",
  1596  						Status: moduletest.Fail,
  1597  						Runs: []*moduletest.Run{
  1598  							{
  1599  								Name:   "test_one",
  1600  								Status: moduletest.Fail,
  1601  							},
  1602  							{
  1603  								Name:   "test_two",
  1604  								Status: moduletest.Skip,
  1605  							},
  1606  							{
  1607  								Name:   "test_three",
  1608  								Status: moduletest.Fail,
  1609  							},
  1610  						},
  1611  					},
  1612  					"other_descriptive_test_name.tftest.hcl": {
  1613  						Name:   "other_descriptive_test_name.tftest.hcl",
  1614  						Status: moduletest.Fail,
  1615  						Runs: []*moduletest.Run{
  1616  							{
  1617  								Name:   "test_one",
  1618  								Status: moduletest.Fail,
  1619  							},
  1620  							{
  1621  								Name:   "test_two",
  1622  								Status: moduletest.Fail,
  1623  							},
  1624  							{
  1625  								Name:   "test_three",
  1626  								Status: moduletest.Skip,
  1627  							},
  1628  						},
  1629  					},
  1630  				},
  1631  			},
  1632  			want: []map[string]interface{}{
  1633  				{
  1634  					"@level":   "info",
  1635  					"@message": "Failure! 0 passed, 4 failed, 2 skipped.",
  1636  					"@module":  "terraform.ui",
  1637  					"test_summary": map[string]interface{}{
  1638  						"status":  "fail",
  1639  						"errored": 0.0,
  1640  						"failed":  4.0,
  1641  						"passed":  0.0,
  1642  						"skipped": 2.0,
  1643  					},
  1644  					"type": "test_summary",
  1645  				},
  1646  			},
  1647  		},
  1648  
  1649  		"failed, passed and skipped tests": {
  1650  			suite: &moduletest.Suite{
  1651  				Status: moduletest.Fail,
  1652  				Files: map[string]*moduletest.File{
  1653  					"descriptive_test_name.tftest.hcl": {
  1654  						Name:   "descriptive_test_name.tftest.hcl",
  1655  						Status: moduletest.Fail,
  1656  						Runs: []*moduletest.Run{
  1657  							{
  1658  								Name:   "test_one",
  1659  								Status: moduletest.Fail,
  1660  							},
  1661  							{
  1662  								Name:   "test_two",
  1663  								Status: moduletest.Pass,
  1664  							},
  1665  							{
  1666  								Name:   "test_three",
  1667  								Status: moduletest.Skip,
  1668  							},
  1669  						},
  1670  					},
  1671  					"other_descriptive_test_name.tftest.hcl": {
  1672  						Name:   "other_descriptive_test_name.tftest.hcl",
  1673  						Status: moduletest.Fail,
  1674  						Runs: []*moduletest.Run{
  1675  							{
  1676  								Name:   "test_one",
  1677  								Status: moduletest.Skip,
  1678  							},
  1679  							{
  1680  								Name:   "test_two",
  1681  								Status: moduletest.Fail,
  1682  							},
  1683  							{
  1684  								Name:   "test_three",
  1685  								Status: moduletest.Pass,
  1686  							},
  1687  						},
  1688  					},
  1689  				},
  1690  			},
  1691  			want: []map[string]interface{}{
  1692  				{
  1693  					"@level":   "info",
  1694  					"@message": "Failure! 2 passed, 2 failed, 2 skipped.",
  1695  					"@module":  "terraform.ui",
  1696  					"test_summary": map[string]interface{}{
  1697  						"status":  "fail",
  1698  						"errored": 0.0,
  1699  						"failed":  2.0,
  1700  						"passed":  2.0,
  1701  						"skipped": 2.0,
  1702  					},
  1703  					"type": "test_summary",
  1704  				},
  1705  			},
  1706  		},
  1707  
  1708  		"failed and errored tests": {
  1709  			suite: &moduletest.Suite{
  1710  				Status: moduletest.Error,
  1711  				Files: map[string]*moduletest.File{
  1712  					"descriptive_test_name.tftest.hcl": {
  1713  						Name:   "descriptive_test_name.tftest.hcl",
  1714  						Status: moduletest.Error,
  1715  						Runs: []*moduletest.Run{
  1716  							{
  1717  								Name:   "test_one",
  1718  								Status: moduletest.Fail,
  1719  							},
  1720  							{
  1721  								Name:   "test_two",
  1722  								Status: moduletest.Error,
  1723  							},
  1724  							{
  1725  								Name:   "test_three",
  1726  								Status: moduletest.Fail,
  1727  							},
  1728  						},
  1729  					},
  1730  					"other_descriptive_test_name.tftest.hcl": {
  1731  						Name:   "other_descriptive_test_name.tftest.hcl",
  1732  						Status: moduletest.Error,
  1733  						Runs: []*moduletest.Run{
  1734  							{
  1735  								Name:   "test_one",
  1736  								Status: moduletest.Fail,
  1737  							},
  1738  							{
  1739  								Name:   "test_two",
  1740  								Status: moduletest.Error,
  1741  							},
  1742  							{
  1743  								Name:   "test_three",
  1744  								Status: moduletest.Error,
  1745  							},
  1746  						},
  1747  					},
  1748  				},
  1749  			},
  1750  			want: []map[string]interface{}{
  1751  				{
  1752  					"@level":   "info",
  1753  					"@message": "Failure! 0 passed, 6 failed.",
  1754  					"@module":  "terraform.ui",
  1755  					"test_summary": map[string]interface{}{
  1756  						"status":  "error",
  1757  						"errored": 3.0,
  1758  						"failed":  3.0,
  1759  						"passed":  0.0,
  1760  						"skipped": 0.0,
  1761  					},
  1762  					"type": "test_summary",
  1763  				},
  1764  			},
  1765  		},
  1766  
  1767  		"failed, errored, passed, and skipped tests": {
  1768  			suite: &moduletest.Suite{
  1769  				Status: moduletest.Error,
  1770  				Files: map[string]*moduletest.File{
  1771  					"descriptive_test_name.tftest.hcl": {
  1772  						Name:   "descriptive_test_name.tftest.hcl",
  1773  						Status: moduletest.Fail,
  1774  						Runs: []*moduletest.Run{
  1775  							{
  1776  								Name:   "test_one",
  1777  								Status: moduletest.Pass,
  1778  							},
  1779  							{
  1780  								Name:   "test_two",
  1781  								Status: moduletest.Pass,
  1782  							},
  1783  							{
  1784  								Name:   "test_three",
  1785  								Status: moduletest.Fail,
  1786  							},
  1787  						},
  1788  					},
  1789  					"other_descriptive_test_name.tftest.hcl": {
  1790  						Name:   "other_descriptive_test_name.tftest.hcl",
  1791  						Status: moduletest.Error,
  1792  						Runs: []*moduletest.Run{
  1793  							{
  1794  								Name:   "test_one",
  1795  								Status: moduletest.Error,
  1796  							},
  1797  							{
  1798  								Name:   "test_two",
  1799  								Status: moduletest.Skip,
  1800  							},
  1801  							{
  1802  								Name:   "test_three",
  1803  								Status: moduletest.Skip,
  1804  							},
  1805  						},
  1806  					},
  1807  				},
  1808  			},
  1809  			want: []map[string]interface{}{
  1810  				{
  1811  					"@level":   "info",
  1812  					"@message": "Failure! 2 passed, 2 failed, 2 skipped.",
  1813  					"@module":  "terraform.ui",
  1814  					"test_summary": map[string]interface{}{
  1815  						"status":  "error",
  1816  						"errored": 1.0,
  1817  						"failed":  1.0,
  1818  						"passed":  2.0,
  1819  						"skipped": 2.0,
  1820  					},
  1821  					"type": "test_summary",
  1822  				},
  1823  			},
  1824  		},
  1825  	}
  1826  	for name, tc := range tcs {
  1827  		t.Run(name, func(t *testing.T) {
  1828  			streams, done := terminal.StreamsForTesting(t)
  1829  			view := NewTest(arguments.ViewJSON, NewView(streams))
  1830  
  1831  			view.Conclusion(tc.suite)
  1832  			testJSONViewOutputEquals(t, done(t).All(), tc.want)
  1833  		})
  1834  	}
  1835  }
  1836  
  1837  func TestTestJSON_DestroySummary(t *testing.T) {
  1838  	tcs := map[string]struct {
  1839  		file  *moduletest.File
  1840  		run   *moduletest.Run
  1841  		state *states.State
  1842  		diags tfdiags.Diagnostics
  1843  		want  []map[string]interface{}
  1844  	}{
  1845  		"empty_state_only_warnings": {
  1846  			diags: tfdiags.Diagnostics{
  1847  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "something not very bad happened"),
  1848  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "something not very bad happened again"),
  1849  			},
  1850  			file:  &moduletest.File{Name: "main.tftest.hcl"},
  1851  			state: states.NewState(),
  1852  			want: []map[string]interface{}{
  1853  				{
  1854  					"@level":    "warn",
  1855  					"@message":  "Warning: first warning",
  1856  					"@module":   "terraform.ui",
  1857  					"@testfile": "main.tftest.hcl",
  1858  					"diagnostic": map[string]interface{}{
  1859  						"detail":   "something not very bad happened",
  1860  						"severity": "warning",
  1861  						"summary":  "first warning",
  1862  					},
  1863  					"type": "diagnostic",
  1864  				},
  1865  				{
  1866  					"@level":    "warn",
  1867  					"@message":  "Warning: second warning",
  1868  					"@module":   "terraform.ui",
  1869  					"@testfile": "main.tftest.hcl",
  1870  					"diagnostic": map[string]interface{}{
  1871  						"detail":   "something not very bad happened again",
  1872  						"severity": "warning",
  1873  						"summary":  "second warning",
  1874  					},
  1875  					"type": "diagnostic",
  1876  				},
  1877  			},
  1878  		},
  1879  		"empty_state_with_errors": {
  1880  			diags: tfdiags.Diagnostics{
  1881  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "something not very bad happened"),
  1882  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "something not very bad happened again"),
  1883  				tfdiags.Sourceless(tfdiags.Error, "first error", "this time it is very bad"),
  1884  			},
  1885  			file:  &moduletest.File{Name: "main.tftest.hcl"},
  1886  			state: states.NewState(),
  1887  			want: []map[string]interface{}{
  1888  				{
  1889  					"@level":    "warn",
  1890  					"@message":  "Warning: first warning",
  1891  					"@module":   "terraform.ui",
  1892  					"@testfile": "main.tftest.hcl",
  1893  					"diagnostic": map[string]interface{}{
  1894  						"detail":   "something not very bad happened",
  1895  						"severity": "warning",
  1896  						"summary":  "first warning",
  1897  					},
  1898  					"type": "diagnostic",
  1899  				},
  1900  				{
  1901  					"@level":    "warn",
  1902  					"@message":  "Warning: second warning",
  1903  					"@module":   "terraform.ui",
  1904  					"@testfile": "main.tftest.hcl",
  1905  					"diagnostic": map[string]interface{}{
  1906  						"detail":   "something not very bad happened again",
  1907  						"severity": "warning",
  1908  						"summary":  "second warning",
  1909  					},
  1910  					"type": "diagnostic",
  1911  				},
  1912  				{
  1913  					"@level":    "error",
  1914  					"@message":  "Error: first error",
  1915  					"@module":   "terraform.ui",
  1916  					"@testfile": "main.tftest.hcl",
  1917  					"diagnostic": map[string]interface{}{
  1918  						"detail":   "this time it is very bad",
  1919  						"severity": "error",
  1920  						"summary":  "first error",
  1921  					},
  1922  					"type": "diagnostic",
  1923  				},
  1924  			},
  1925  		},
  1926  		"state_from_run": {
  1927  			file: &moduletest.File{Name: "main.tftest.hcl"},
  1928  			run:  &moduletest.Run{Name: "run_block"},
  1929  			state: states.BuildState(func(state *states.SyncState) {
  1930  				state.SetResourceInstanceCurrent(
  1931  					addrs.Resource{
  1932  						Mode: addrs.ManagedResourceMode,
  1933  						Type: "test",
  1934  						Name: "foo",
  1935  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1936  					&states.ResourceInstanceObjectSrc{
  1937  						Status: states.ObjectReady,
  1938  					},
  1939  					addrs.AbsProviderConfig{
  1940  						Module:   addrs.RootModule,
  1941  						Provider: addrs.NewDefaultProvider("test"),
  1942  					})
  1943  			}),
  1944  			want: []map[string]interface{}{
  1945  				{
  1946  					"@level":    "error",
  1947  					"@message":  "Terraform left some resources in state after executing main.tftest.hcl/run_block, they need to be cleaned up manually.",
  1948  					"@module":   "terraform.ui",
  1949  					"@testfile": "main.tftest.hcl",
  1950  					"@testrun":  "run_block",
  1951  					"test_cleanup": map[string]interface{}{
  1952  						"failed_resources": []interface{}{
  1953  							map[string]interface{}{
  1954  								"instance": "test.foo",
  1955  							},
  1956  						},
  1957  					},
  1958  					"type": "test_cleanup",
  1959  				},
  1960  			},
  1961  		},
  1962  		"state_only_warnings": {
  1963  			diags: tfdiags.Diagnostics{
  1964  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "something not very bad happened"),
  1965  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "something not very bad happened again"),
  1966  			},
  1967  			file: &moduletest.File{Name: "main.tftest.hcl"},
  1968  			state: states.BuildState(func(state *states.SyncState) {
  1969  				state.SetResourceInstanceCurrent(
  1970  					addrs.Resource{
  1971  						Mode: addrs.ManagedResourceMode,
  1972  						Type: "test",
  1973  						Name: "foo",
  1974  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1975  					&states.ResourceInstanceObjectSrc{
  1976  						Status: states.ObjectReady,
  1977  					},
  1978  					addrs.AbsProviderConfig{
  1979  						Module:   addrs.RootModule,
  1980  						Provider: addrs.NewDefaultProvider("test"),
  1981  					})
  1982  				state.SetResourceInstanceCurrent(
  1983  					addrs.Resource{
  1984  						Mode: addrs.ManagedResourceMode,
  1985  						Type: "test",
  1986  						Name: "bar",
  1987  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1988  					&states.ResourceInstanceObjectSrc{
  1989  						Status: states.ObjectReady,
  1990  					},
  1991  					addrs.AbsProviderConfig{
  1992  						Module:   addrs.RootModule,
  1993  						Provider: addrs.NewDefaultProvider("test"),
  1994  					})
  1995  				state.SetResourceInstanceDeposed(
  1996  					addrs.Resource{
  1997  						Mode: addrs.ManagedResourceMode,
  1998  						Type: "test",
  1999  						Name: "bar",
  2000  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  2001  					"0fcb640a",
  2002  					&states.ResourceInstanceObjectSrc{
  2003  						Status: states.ObjectReady,
  2004  					},
  2005  					addrs.AbsProviderConfig{
  2006  						Module:   addrs.RootModule,
  2007  						Provider: addrs.NewDefaultProvider("test"),
  2008  					})
  2009  			}),
  2010  			want: []map[string]interface{}{
  2011  				{
  2012  					"@level":    "error",
  2013  					"@message":  "Terraform left some resources in state after executing main.tftest.hcl, they need to be cleaned up manually.",
  2014  					"@module":   "terraform.ui",
  2015  					"@testfile": "main.tftest.hcl",
  2016  					"test_cleanup": map[string]interface{}{
  2017  						"failed_resources": []interface{}{
  2018  							map[string]interface{}{
  2019  								"instance": "test.bar",
  2020  							},
  2021  							map[string]interface{}{
  2022  								"instance":    "test.bar",
  2023  								"deposed_key": "0fcb640a",
  2024  							},
  2025  							map[string]interface{}{
  2026  								"instance": "test.foo",
  2027  							},
  2028  						},
  2029  					},
  2030  					"type": "test_cleanup",
  2031  				},
  2032  				{
  2033  					"@level":    "warn",
  2034  					"@message":  "Warning: first warning",
  2035  					"@module":   "terraform.ui",
  2036  					"@testfile": "main.tftest.hcl",
  2037  					"diagnostic": map[string]interface{}{
  2038  						"detail":   "something not very bad happened",
  2039  						"severity": "warning",
  2040  						"summary":  "first warning",
  2041  					},
  2042  					"type": "diagnostic",
  2043  				},
  2044  				{
  2045  					"@level":    "warn",
  2046  					"@message":  "Warning: second warning",
  2047  					"@module":   "terraform.ui",
  2048  					"@testfile": "main.tftest.hcl",
  2049  					"diagnostic": map[string]interface{}{
  2050  						"detail":   "something not very bad happened again",
  2051  						"severity": "warning",
  2052  						"summary":  "second warning",
  2053  					},
  2054  					"type": "diagnostic",
  2055  				},
  2056  			},
  2057  		},
  2058  		"state_with_errors": {
  2059  			diags: tfdiags.Diagnostics{
  2060  				tfdiags.Sourceless(tfdiags.Warning, "first warning", "something not very bad happened"),
  2061  				tfdiags.Sourceless(tfdiags.Warning, "second warning", "something not very bad happened again"),
  2062  				tfdiags.Sourceless(tfdiags.Error, "first error", "this time it is very bad"),
  2063  			},
  2064  			file: &moduletest.File{Name: "main.tftest.hcl"},
  2065  			state: states.BuildState(func(state *states.SyncState) {
  2066  				state.SetResourceInstanceCurrent(
  2067  					addrs.Resource{
  2068  						Mode: addrs.ManagedResourceMode,
  2069  						Type: "test",
  2070  						Name: "foo",
  2071  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  2072  					&states.ResourceInstanceObjectSrc{
  2073  						Status: states.ObjectReady,
  2074  					},
  2075  					addrs.AbsProviderConfig{
  2076  						Module:   addrs.RootModule,
  2077  						Provider: addrs.NewDefaultProvider("test"),
  2078  					})
  2079  				state.SetResourceInstanceCurrent(
  2080  					addrs.Resource{
  2081  						Mode: addrs.ManagedResourceMode,
  2082  						Type: "test",
  2083  						Name: "bar",
  2084  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  2085  					&states.ResourceInstanceObjectSrc{
  2086  						Status: states.ObjectReady,
  2087  					},
  2088  					addrs.AbsProviderConfig{
  2089  						Module:   addrs.RootModule,
  2090  						Provider: addrs.NewDefaultProvider("test"),
  2091  					})
  2092  				state.SetResourceInstanceDeposed(
  2093  					addrs.Resource{
  2094  						Mode: addrs.ManagedResourceMode,
  2095  						Type: "test",
  2096  						Name: "bar",
  2097  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  2098  					"0fcb640a",
  2099  					&states.ResourceInstanceObjectSrc{
  2100  						Status: states.ObjectReady,
  2101  					},
  2102  					addrs.AbsProviderConfig{
  2103  						Module:   addrs.RootModule,
  2104  						Provider: addrs.NewDefaultProvider("test"),
  2105  					})
  2106  			}),
  2107  			want: []map[string]interface{}{
  2108  				{
  2109  					"@level":    "error",
  2110  					"@message":  "Terraform left some resources in state after executing main.tftest.hcl, they need to be cleaned up manually.",
  2111  					"@module":   "terraform.ui",
  2112  					"@testfile": "main.tftest.hcl",
  2113  					"test_cleanup": map[string]interface{}{
  2114  						"failed_resources": []interface{}{
  2115  							map[string]interface{}{
  2116  								"instance": "test.bar",
  2117  							},
  2118  							map[string]interface{}{
  2119  								"instance":    "test.bar",
  2120  								"deposed_key": "0fcb640a",
  2121  							},
  2122  							map[string]interface{}{
  2123  								"instance": "test.foo",
  2124  							},
  2125  						},
  2126  					},
  2127  					"type": "test_cleanup",
  2128  				},
  2129  				{
  2130  					"@level":    "warn",
  2131  					"@message":  "Warning: first warning",
  2132  					"@module":   "terraform.ui",
  2133  					"@testfile": "main.tftest.hcl",
  2134  					"diagnostic": map[string]interface{}{
  2135  						"detail":   "something not very bad happened",
  2136  						"severity": "warning",
  2137  						"summary":  "first warning",
  2138  					},
  2139  					"type": "diagnostic",
  2140  				},
  2141  				{
  2142  					"@level":    "warn",
  2143  					"@message":  "Warning: second warning",
  2144  					"@module":   "terraform.ui",
  2145  					"@testfile": "main.tftest.hcl",
  2146  					"diagnostic": map[string]interface{}{
  2147  						"detail":   "something not very bad happened again",
  2148  						"severity": "warning",
  2149  						"summary":  "second warning",
  2150  					},
  2151  					"type": "diagnostic",
  2152  				},
  2153  				{
  2154  					"@level":    "error",
  2155  					"@message":  "Error: first error",
  2156  					"@module":   "terraform.ui",
  2157  					"@testfile": "main.tftest.hcl",
  2158  					"diagnostic": map[string]interface{}{
  2159  						"detail":   "this time it is very bad",
  2160  						"severity": "error",
  2161  						"summary":  "first error",
  2162  					},
  2163  					"type": "diagnostic",
  2164  				},
  2165  			},
  2166  		},
  2167  	}
  2168  	for name, tc := range tcs {
  2169  		t.Run(name, func(t *testing.T) {
  2170  			streams, done := terminal.StreamsForTesting(t)
  2171  			view := NewTest(arguments.ViewJSON, NewView(streams))
  2172  
  2173  			view.DestroySummary(tc.diags, tc.run, tc.file, tc.state)
  2174  			testJSONViewOutputEquals(t, done(t).All(), tc.want)
  2175  		})
  2176  	}
  2177  }
  2178  
  2179  func TestTestJSON_File(t *testing.T) {
  2180  	tcs := map[string]struct {
  2181  		file *moduletest.File
  2182  		want []map[string]interface{}
  2183  	}{
  2184  		"pass": {
  2185  			file: &moduletest.File{Name: "main.tf", Status: moduletest.Pass},
  2186  			want: []map[string]interface{}{
  2187  				{
  2188  					"@level":    "info",
  2189  					"@message":  "main.tf... pass",
  2190  					"@module":   "terraform.ui",
  2191  					"@testfile": "main.tf",
  2192  					"test_file": map[string]interface{}{
  2193  						"path":   "main.tf",
  2194  						"status": "pass",
  2195  					},
  2196  					"type": "test_file",
  2197  				},
  2198  			},
  2199  		},
  2200  
  2201  		"pending": {
  2202  			file: &moduletest.File{Name: "main.tf", Status: moduletest.Pending},
  2203  			want: []map[string]interface{}{
  2204  				{
  2205  					"@level":    "info",
  2206  					"@message":  "main.tf... pending",
  2207  					"@module":   "terraform.ui",
  2208  					"@testfile": "main.tf",
  2209  					"test_file": map[string]interface{}{
  2210  						"path":   "main.tf",
  2211  						"status": "pending",
  2212  					},
  2213  					"type": "test_file",
  2214  				},
  2215  			},
  2216  		},
  2217  
  2218  		"skip": {
  2219  			file: &moduletest.File{Name: "main.tf", Status: moduletest.Skip},
  2220  			want: []map[string]interface{}{
  2221  				{
  2222  					"@level":    "info",
  2223  					"@message":  "main.tf... skip",
  2224  					"@module":   "terraform.ui",
  2225  					"@testfile": "main.tf",
  2226  					"test_file": map[string]interface{}{
  2227  						"path":   "main.tf",
  2228  						"status": "skip",
  2229  					},
  2230  					"type": "test_file",
  2231  				},
  2232  			},
  2233  		},
  2234  
  2235  		"fail": {
  2236  			file: &moduletest.File{Name: "main.tf", Status: moduletest.Fail},
  2237  			want: []map[string]interface{}{
  2238  				{
  2239  					"@level":    "info",
  2240  					"@message":  "main.tf... fail",
  2241  					"@module":   "terraform.ui",
  2242  					"@testfile": "main.tf",
  2243  					"test_file": map[string]interface{}{
  2244  						"path":   "main.tf",
  2245  						"status": "fail",
  2246  					},
  2247  					"type": "test_file",
  2248  				},
  2249  			},
  2250  		},
  2251  
  2252  		"error": {
  2253  			file: &moduletest.File{Name: "main.tf", Status: moduletest.Error},
  2254  			want: []map[string]interface{}{
  2255  				{
  2256  					"@level":    "info",
  2257  					"@message":  "main.tf... fail",
  2258  					"@module":   "terraform.ui",
  2259  					"@testfile": "main.tf",
  2260  					"test_file": map[string]interface{}{
  2261  						"path":   "main.tf",
  2262  						"status": "error",
  2263  					},
  2264  					"type": "test_file",
  2265  				},
  2266  			},
  2267  		},
  2268  	}
  2269  	for name, tc := range tcs {
  2270  		t.Run(name, func(t *testing.T) {
  2271  			streams, done := terminal.StreamsForTesting(t)
  2272  			view := NewTest(arguments.ViewJSON, NewView(streams))
  2273  
  2274  			view.File(tc.file)
  2275  			testJSONViewOutputEquals(t, done(t).All(), tc.want)
  2276  		})
  2277  	}
  2278  }
  2279  
  2280  func TestTestJSON_Run(t *testing.T) {
  2281  	tcs := map[string]struct {
  2282  		run  *moduletest.Run
  2283  		want []map[string]interface{}
  2284  	}{
  2285  		"pass": {
  2286  			run: &moduletest.Run{Name: "run_block", Status: moduletest.Pass},
  2287  			want: []map[string]interface{}{
  2288  				{
  2289  					"@level":    "info",
  2290  					"@message":  "  \"run_block\"... pass",
  2291  					"@module":   "terraform.ui",
  2292  					"@testfile": "main.tftest.hcl",
  2293  					"@testrun":  "run_block",
  2294  					"test_run": map[string]interface{}{
  2295  						"path":   "main.tftest.hcl",
  2296  						"run":    "run_block",
  2297  						"status": "pass",
  2298  					},
  2299  					"type": "test_run",
  2300  				},
  2301  			},
  2302  		},
  2303  
  2304  		"pass_with_diags": {
  2305  			run: &moduletest.Run{
  2306  				Name:        "run_block",
  2307  				Status:      moduletest.Pass,
  2308  				Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Warning, "a warning occurred", "some warning happened during this test")},
  2309  			},
  2310  			want: []map[string]interface{}{
  2311  				{
  2312  					"@level":    "info",
  2313  					"@message":  "  \"run_block\"... pass",
  2314  					"@module":   "terraform.ui",
  2315  					"@testfile": "main.tftest.hcl",
  2316  					"@testrun":  "run_block",
  2317  					"test_run": map[string]interface{}{
  2318  						"path":   "main.tftest.hcl",
  2319  						"run":    "run_block",
  2320  						"status": "pass",
  2321  					},
  2322  					"type": "test_run",
  2323  				},
  2324  				{
  2325  					"@level":    "warn",
  2326  					"@message":  "Warning: a warning occurred",
  2327  					"@module":   "terraform.ui",
  2328  					"@testfile": "main.tftest.hcl",
  2329  					"@testrun":  "run_block",
  2330  					"diagnostic": map[string]interface{}{
  2331  						"detail":   "some warning happened during this test",
  2332  						"severity": "warning",
  2333  						"summary":  "a warning occurred",
  2334  					},
  2335  					"type": "diagnostic",
  2336  				},
  2337  			},
  2338  		},
  2339  
  2340  		"pending": {
  2341  			run: &moduletest.Run{Name: "run_block", Status: moduletest.Pending},
  2342  			want: []map[string]interface{}{
  2343  				{
  2344  					"@level":    "info",
  2345  					"@message":  "  \"run_block\"... pending",
  2346  					"@module":   "terraform.ui",
  2347  					"@testfile": "main.tftest.hcl",
  2348  					"@testrun":  "run_block",
  2349  					"test_run": map[string]interface{}{
  2350  						"path":   "main.tftest.hcl",
  2351  						"run":    "run_block",
  2352  						"status": "pending",
  2353  					},
  2354  					"type": "test_run",
  2355  				},
  2356  			},
  2357  		},
  2358  
  2359  		"skip": {
  2360  			run: &moduletest.Run{Name: "run_block", Status: moduletest.Skip},
  2361  			want: []map[string]interface{}{
  2362  				{
  2363  					"@level":    "info",
  2364  					"@message":  "  \"run_block\"... skip",
  2365  					"@module":   "terraform.ui",
  2366  					"@testfile": "main.tftest.hcl",
  2367  					"@testrun":  "run_block",
  2368  					"test_run": map[string]interface{}{
  2369  						"path":   "main.tftest.hcl",
  2370  						"run":    "run_block",
  2371  						"status": "skip",
  2372  					},
  2373  					"type": "test_run",
  2374  				},
  2375  			},
  2376  		},
  2377  
  2378  		"fail": {
  2379  			run: &moduletest.Run{Name: "run_block", Status: moduletest.Fail},
  2380  			want: []map[string]interface{}{
  2381  				{
  2382  					"@level":    "info",
  2383  					"@message":  "  \"run_block\"... fail",
  2384  					"@module":   "terraform.ui",
  2385  					"@testfile": "main.tftest.hcl",
  2386  					"@testrun":  "run_block",
  2387  					"test_run": map[string]interface{}{
  2388  						"path":   "main.tftest.hcl",
  2389  						"run":    "run_block",
  2390  						"status": "fail",
  2391  					},
  2392  					"type": "test_run",
  2393  				},
  2394  			},
  2395  		},
  2396  
  2397  		"fail_with_diags": {
  2398  			run: &moduletest.Run{
  2399  				Name:   "run_block",
  2400  				Status: moduletest.Fail,
  2401  				Diagnostics: tfdiags.Diagnostics{
  2402  					tfdiags.Sourceless(tfdiags.Error, "a comparison failed", "details details details"),
  2403  					tfdiags.Sourceless(tfdiags.Error, "a second comparison failed", "other details"),
  2404  				},
  2405  			},
  2406  			want: []map[string]interface{}{
  2407  				{
  2408  					"@level":    "info",
  2409  					"@message":  "  \"run_block\"... fail",
  2410  					"@module":   "terraform.ui",
  2411  					"@testfile": "main.tftest.hcl",
  2412  					"@testrun":  "run_block",
  2413  					"test_run": map[string]interface{}{
  2414  						"path":   "main.tftest.hcl",
  2415  						"run":    "run_block",
  2416  						"status": "fail",
  2417  					},
  2418  					"type": "test_run",
  2419  				},
  2420  				{
  2421  					"@level":    "error",
  2422  					"@message":  "Error: a comparison failed",
  2423  					"@module":   "terraform.ui",
  2424  					"@testfile": "main.tftest.hcl",
  2425  					"@testrun":  "run_block",
  2426  					"diagnostic": map[string]interface{}{
  2427  						"detail":   "details details details",
  2428  						"severity": "error",
  2429  						"summary":  "a comparison failed",
  2430  					},
  2431  					"type": "diagnostic",
  2432  				},
  2433  				{
  2434  					"@level":    "error",
  2435  					"@message":  "Error: a second comparison failed",
  2436  					"@module":   "terraform.ui",
  2437  					"@testfile": "main.tftest.hcl",
  2438  					"@testrun":  "run_block",
  2439  					"diagnostic": map[string]interface{}{
  2440  						"detail":   "other details",
  2441  						"severity": "error",
  2442  						"summary":  "a second comparison failed",
  2443  					},
  2444  					"type": "diagnostic",
  2445  				},
  2446  			},
  2447  		},
  2448  
  2449  		"error": {
  2450  			run: &moduletest.Run{Name: "run_block", Status: moduletest.Error},
  2451  			want: []map[string]interface{}{
  2452  				{
  2453  					"@level":    "info",
  2454  					"@message":  "  \"run_block\"... fail",
  2455  					"@module":   "terraform.ui",
  2456  					"@testfile": "main.tftest.hcl",
  2457  					"@testrun":  "run_block",
  2458  					"test_run": map[string]interface{}{
  2459  						"path":   "main.tftest.hcl",
  2460  						"run":    "run_block",
  2461  						"status": "error",
  2462  					},
  2463  					"type": "test_run",
  2464  				},
  2465  			},
  2466  		},
  2467  
  2468  		"error_with_diags": {
  2469  			run: &moduletest.Run{
  2470  				Name:        "run_block",
  2471  				Status:      moduletest.Error,
  2472  				Diagnostics: tfdiags.Diagnostics{tfdiags.Sourceless(tfdiags.Error, "an error occurred", "something bad happened during this test")},
  2473  			},
  2474  			want: []map[string]interface{}{
  2475  				{
  2476  					"@level":    "info",
  2477  					"@message":  "  \"run_block\"... fail",
  2478  					"@module":   "terraform.ui",
  2479  					"@testfile": "main.tftest.hcl",
  2480  					"@testrun":  "run_block",
  2481  					"test_run": map[string]interface{}{
  2482  						"path":   "main.tftest.hcl",
  2483  						"run":    "run_block",
  2484  						"status": "error",
  2485  					},
  2486  					"type": "test_run",
  2487  				},
  2488  				{
  2489  					"@level":    "error",
  2490  					"@message":  "Error: an error occurred",
  2491  					"@module":   "terraform.ui",
  2492  					"@testfile": "main.tftest.hcl",
  2493  					"@testrun":  "run_block",
  2494  					"diagnostic": map[string]interface{}{
  2495  						"detail":   "something bad happened during this test",
  2496  						"severity": "error",
  2497  						"summary":  "an error occurred",
  2498  					},
  2499  					"type": "diagnostic",
  2500  				},
  2501  			},
  2502  		},
  2503  
  2504  		"verbose_plan": {
  2505  			run: &moduletest.Run{
  2506  				Name:   "run_block",
  2507  				Status: moduletest.Pass,
  2508  				Config: &configs.TestRun{
  2509  					Command: configs.PlanTestCommand,
  2510  				},
  2511  				Verbose: &moduletest.Verbose{
  2512  					Plan: &plans.Plan{
  2513  						Changes: &plans.Changes{
  2514  							Resources: []*plans.ResourceInstanceChangeSrc{
  2515  								{
  2516  									Addr: addrs.AbsResourceInstance{
  2517  										Module: addrs.RootModuleInstance,
  2518  										Resource: addrs.ResourceInstance{
  2519  											Resource: addrs.Resource{
  2520  												Mode: addrs.ManagedResourceMode,
  2521  												Type: "test_resource",
  2522  												Name: "creating",
  2523  											},
  2524  										},
  2525  									},
  2526  									PrevRunAddr: addrs.AbsResourceInstance{
  2527  										Module: addrs.RootModuleInstance,
  2528  										Resource: addrs.ResourceInstance{
  2529  											Resource: addrs.Resource{
  2530  												Mode: addrs.ManagedResourceMode,
  2531  												Type: "test_resource",
  2532  												Name: "creating",
  2533  											},
  2534  										},
  2535  									},
  2536  									ProviderAddr: addrs.AbsProviderConfig{
  2537  										Module: addrs.RootModule,
  2538  										Provider: addrs.Provider{
  2539  											Hostname:  addrs.DefaultProviderRegistryHost,
  2540  											Namespace: "hashicorp",
  2541  											Type:      "test",
  2542  										},
  2543  									},
  2544  									ChangeSrc: plans.ChangeSrc{
  2545  										Action: plans.Create,
  2546  										After: dynamicValue(
  2547  											t,
  2548  											cty.ObjectVal(map[string]cty.Value{
  2549  												"value": cty.StringVal("foobar"),
  2550  											}),
  2551  											cty.Object(map[string]cty.Type{
  2552  												"value": cty.String,
  2553  											})),
  2554  									},
  2555  								},
  2556  							},
  2557  						},
  2558  					},
  2559  					State: states.NewState(), // empty state
  2560  					Config: &configs.Config{
  2561  						Module: &configs.Module{
  2562  							ProviderRequirements: &configs.RequiredProviders{},
  2563  						},
  2564  					},
  2565  					Providers: map[addrs.Provider]providers.ProviderSchema{
  2566  						addrs.Provider{
  2567  							Hostname:  addrs.DefaultProviderRegistryHost,
  2568  							Namespace: "hashicorp",
  2569  							Type:      "test",
  2570  						}: {
  2571  							ResourceTypes: map[string]providers.Schema{
  2572  								"test_resource": {
  2573  									Block: &configschema.Block{
  2574  										Attributes: map[string]*configschema.Attribute{
  2575  											"value": {
  2576  												Type: cty.String,
  2577  											},
  2578  										},
  2579  									},
  2580  								},
  2581  							},
  2582  						},
  2583  					},
  2584  				},
  2585  			},
  2586  			want: []map[string]interface{}{
  2587  				{
  2588  					"@level":    "info",
  2589  					"@message":  "  \"run_block\"... pass",
  2590  					"@module":   "terraform.ui",
  2591  					"@testfile": "main.tftest.hcl",
  2592  					"@testrun":  "run_block",
  2593  					"test_run": map[string]interface{}{
  2594  						"path":   "main.tftest.hcl",
  2595  						"run":    "run_block",
  2596  						"status": "pass",
  2597  					},
  2598  					"type": "test_run",
  2599  				},
  2600  				{
  2601  					"@level":    "info",
  2602  					"@message":  "-verbose flag enabled, printing plan",
  2603  					"@module":   "terraform.ui",
  2604  					"@testfile": "main.tftest.hcl",
  2605  					"@testrun":  "run_block",
  2606  					"test_plan": map[string]interface{}{
  2607  						"configuration": map[string]interface{}{
  2608  							"root_module": map[string]interface{}{},
  2609  						},
  2610  						"errored": false,
  2611  						"planned_values": map[string]interface{}{
  2612  							"root_module": map[string]interface{}{
  2613  								"resources": []interface{}{
  2614  									map[string]interface{}{
  2615  										"address":          "test_resource.creating",
  2616  										"mode":             "managed",
  2617  										"name":             "creating",
  2618  										"provider_name":    "registry.terraform.io/hashicorp/test",
  2619  										"schema_version":   0.0,
  2620  										"sensitive_values": map[string]interface{}{},
  2621  										"type":             "test_resource",
  2622  										"values": map[string]interface{}{
  2623  											"value": "foobar",
  2624  										},
  2625  									},
  2626  								},
  2627  							},
  2628  						},
  2629  						"resource_changes": []interface{}{
  2630  							map[string]interface{}{
  2631  								"address": "test_resource.creating",
  2632  								"change": map[string]interface{}{
  2633  									"actions": []interface{}{"create"},
  2634  									"after": map[string]interface{}{
  2635  										"value": "foobar",
  2636  									},
  2637  									"after_sensitive":  map[string]interface{}{},
  2638  									"after_unknown":    map[string]interface{}{},
  2639  									"before":           nil,
  2640  									"before_sensitive": false,
  2641  								},
  2642  								"mode":          "managed",
  2643  								"name":          "creating",
  2644  								"provider_name": "registry.terraform.io/hashicorp/test",
  2645  								"type":          "test_resource",
  2646  							},
  2647  						},
  2648  					},
  2649  					"type": "test_plan",
  2650  				},
  2651  			},
  2652  		},
  2653  		"verbose_apply": {
  2654  			run: &moduletest.Run{
  2655  				Name:   "run_block",
  2656  				Status: moduletest.Pass,
  2657  				Config: &configs.TestRun{
  2658  					Command: configs.ApplyTestCommand,
  2659  				},
  2660  				Verbose: &moduletest.Verbose{
  2661  					Plan: &plans.Plan{}, // empty plan
  2662  					State: states.BuildState(func(state *states.SyncState) {
  2663  						state.SetResourceInstanceCurrent(
  2664  							addrs.AbsResourceInstance{
  2665  								Module: addrs.RootModuleInstance,
  2666  								Resource: addrs.ResourceInstance{
  2667  									Resource: addrs.Resource{
  2668  										Mode: addrs.ManagedResourceMode,
  2669  										Type: "test_resource",
  2670  										Name: "creating",
  2671  									},
  2672  								},
  2673  							},
  2674  							&states.ResourceInstanceObjectSrc{
  2675  								AttrsJSON: []byte(`{"value":"foobar"}`),
  2676  							},
  2677  							addrs.AbsProviderConfig{
  2678  								Module: addrs.RootModule,
  2679  								Provider: addrs.Provider{
  2680  									Hostname:  addrs.DefaultProviderRegistryHost,
  2681  									Namespace: "hashicorp",
  2682  									Type:      "test",
  2683  								},
  2684  							})
  2685  					}),
  2686  					Config: &configs.Config{
  2687  						Module: &configs.Module{},
  2688  					},
  2689  					Providers: map[addrs.Provider]providers.ProviderSchema{
  2690  						addrs.Provider{
  2691  							Hostname:  addrs.DefaultProviderRegistryHost,
  2692  							Namespace: "hashicorp",
  2693  							Type:      "test",
  2694  						}: {
  2695  							ResourceTypes: map[string]providers.Schema{
  2696  								"test_resource": {
  2697  									Block: &configschema.Block{
  2698  										Attributes: map[string]*configschema.Attribute{
  2699  											"value": {
  2700  												Type: cty.String,
  2701  											},
  2702  										},
  2703  									},
  2704  								},
  2705  							},
  2706  						},
  2707  					},
  2708  				},
  2709  			},
  2710  			want: []map[string]interface{}{
  2711  				{
  2712  					"@level":    "info",
  2713  					"@message":  "  \"run_block\"... pass",
  2714  					"@module":   "terraform.ui",
  2715  					"@testfile": "main.tftest.hcl",
  2716  					"@testrun":  "run_block",
  2717  					"test_run": map[string]interface{}{
  2718  						"path":   "main.tftest.hcl",
  2719  						"run":    "run_block",
  2720  						"status": "pass",
  2721  					},
  2722  					"type": "test_run",
  2723  				},
  2724  				{
  2725  					"@level":    "info",
  2726  					"@message":  "-verbose flag enabled, printing state",
  2727  					"@module":   "terraform.ui",
  2728  					"@testfile": "main.tftest.hcl",
  2729  					"@testrun":  "run_block",
  2730  					"test_state": map[string]interface{}{
  2731  						"values": map[string]interface{}{
  2732  							"root_module": map[string]interface{}{
  2733  								"resources": []interface{}{
  2734  									map[string]interface{}{
  2735  										"address":          "test_resource.creating",
  2736  										"mode":             "managed",
  2737  										"name":             "creating",
  2738  										"provider_name":    "registry.terraform.io/hashicorp/test",
  2739  										"schema_version":   0.0,
  2740  										"sensitive_values": map[string]interface{}{},
  2741  										"type":             "test_resource",
  2742  										"values": map[string]interface{}{
  2743  											"value": "foobar",
  2744  										},
  2745  									},
  2746  								},
  2747  							},
  2748  						},
  2749  					},
  2750  					"type": "test_state",
  2751  				},
  2752  			},
  2753  		},
  2754  	}
  2755  	for name, tc := range tcs {
  2756  		t.Run(name, func(t *testing.T) {
  2757  			streams, done := terminal.StreamsForTesting(t)
  2758  			view := NewTest(arguments.ViewJSON, NewView(streams))
  2759  
  2760  			file := &moduletest.File{Name: "main.tftest.hcl"}
  2761  
  2762  			view.Run(tc.run, file)
  2763  			testJSONViewOutputEquals(t, done(t).All(), tc.want, cmp.FilterPath(func(path cmp.Path) bool {
  2764  				return strings.Contains(path.Last().String(), "version") || strings.Contains(path.Last().String(), "timestamp")
  2765  			}, cmp.Ignore()))
  2766  		})
  2767  	}
  2768  }
  2769  
  2770  func TestTestJSON_FatalInterruptSummary(t *testing.T) {
  2771  	tcs := map[string]struct {
  2772  		states  map[*moduletest.Run]*states.State
  2773  		changes []*plans.ResourceInstanceChangeSrc
  2774  		want    []map[string]interface{}
  2775  	}{
  2776  		"no_state_only_plan": {
  2777  			states: make(map[*moduletest.Run]*states.State),
  2778  			changes: []*plans.ResourceInstanceChangeSrc{
  2779  				{
  2780  					Addr: addrs.AbsResourceInstance{
  2781  						Module: addrs.RootModuleInstance,
  2782  						Resource: addrs.ResourceInstance{
  2783  							Resource: addrs.Resource{
  2784  								Mode: addrs.ManagedResourceMode,
  2785  								Type: "test_instance",
  2786  								Name: "one",
  2787  							},
  2788  						},
  2789  					},
  2790  					ChangeSrc: plans.ChangeSrc{
  2791  						Action: plans.Create,
  2792  					},
  2793  				},
  2794  				{
  2795  					Addr: addrs.AbsResourceInstance{
  2796  						Module: addrs.RootModuleInstance,
  2797  						Resource: addrs.ResourceInstance{
  2798  							Resource: addrs.Resource{
  2799  								Mode: addrs.ManagedResourceMode,
  2800  								Type: "test_instance",
  2801  								Name: "two",
  2802  							},
  2803  						},
  2804  					},
  2805  					ChangeSrc: plans.ChangeSrc{
  2806  						Action: plans.Create,
  2807  					},
  2808  				},
  2809  			},
  2810  			want: []map[string]interface{}{
  2811  				{
  2812  					"@level":    "error",
  2813  					"@message":  "Terraform was interrupted during test execution, and may not have performed the expected cleanup operations.",
  2814  					"@module":   "terraform.ui",
  2815  					"@testfile": "main.tftest.hcl",
  2816  					"test_interrupt": map[string]interface{}{
  2817  						"planned": []interface{}{
  2818  							"test_instance.one",
  2819  							"test_instance.two",
  2820  						},
  2821  					},
  2822  					"type": "test_interrupt",
  2823  				},
  2824  			},
  2825  		},
  2826  		"file_state_no_plan": {
  2827  			states: map[*moduletest.Run]*states.State{
  2828  				nil: states.BuildState(func(state *states.SyncState) {
  2829  					state.SetResourceInstanceCurrent(
  2830  						addrs.AbsResourceInstance{
  2831  							Module: addrs.RootModuleInstance,
  2832  							Resource: addrs.ResourceInstance{
  2833  								Resource: addrs.Resource{
  2834  									Mode: addrs.ManagedResourceMode,
  2835  									Type: "test_instance",
  2836  									Name: "one",
  2837  								},
  2838  							},
  2839  						},
  2840  						&states.ResourceInstanceObjectSrc{},
  2841  						addrs.AbsProviderConfig{})
  2842  
  2843  					state.SetResourceInstanceCurrent(
  2844  						addrs.AbsResourceInstance{
  2845  							Module: addrs.RootModuleInstance,
  2846  							Resource: addrs.ResourceInstance{
  2847  								Resource: addrs.Resource{
  2848  									Mode: addrs.ManagedResourceMode,
  2849  									Type: "test_instance",
  2850  									Name: "two",
  2851  								},
  2852  							},
  2853  						},
  2854  						&states.ResourceInstanceObjectSrc{},
  2855  						addrs.AbsProviderConfig{})
  2856  				}),
  2857  			},
  2858  			changes: nil,
  2859  			want: []map[string]interface{}{
  2860  				{
  2861  					"@level":    "error",
  2862  					"@message":  "Terraform was interrupted during test execution, and may not have performed the expected cleanup operations.",
  2863  					"@module":   "terraform.ui",
  2864  					"@testfile": "main.tftest.hcl",
  2865  					"test_interrupt": map[string]interface{}{
  2866  						"state": []interface{}{
  2867  							map[string]interface{}{
  2868  								"instance": "test_instance.one",
  2869  							},
  2870  							map[string]interface{}{
  2871  								"instance": "test_instance.two",
  2872  							},
  2873  						},
  2874  					},
  2875  					"type": "test_interrupt",
  2876  				},
  2877  			},
  2878  		},
  2879  		"run_states_no_plan": {
  2880  			states: map[*moduletest.Run]*states.State{
  2881  				&moduletest.Run{Name: "setup_block"}: states.BuildState(func(state *states.SyncState) {
  2882  					state.SetResourceInstanceCurrent(
  2883  						addrs.AbsResourceInstance{
  2884  							Module: addrs.RootModuleInstance,
  2885  							Resource: addrs.ResourceInstance{
  2886  								Resource: addrs.Resource{
  2887  									Mode: addrs.ManagedResourceMode,
  2888  									Type: "test_instance",
  2889  									Name: "one",
  2890  								},
  2891  							},
  2892  						},
  2893  						&states.ResourceInstanceObjectSrc{},
  2894  						addrs.AbsProviderConfig{})
  2895  
  2896  					state.SetResourceInstanceCurrent(
  2897  						addrs.AbsResourceInstance{
  2898  							Module: addrs.RootModuleInstance,
  2899  							Resource: addrs.ResourceInstance{
  2900  								Resource: addrs.Resource{
  2901  									Mode: addrs.ManagedResourceMode,
  2902  									Type: "test_instance",
  2903  									Name: "two",
  2904  								},
  2905  							},
  2906  						},
  2907  						&states.ResourceInstanceObjectSrc{},
  2908  						addrs.AbsProviderConfig{})
  2909  				}),
  2910  			},
  2911  			changes: nil,
  2912  			want: []map[string]interface{}{
  2913  				{
  2914  					"@level":    "error",
  2915  					"@message":  "Terraform was interrupted during test execution, and may not have performed the expected cleanup operations.",
  2916  					"@module":   "terraform.ui",
  2917  					"@testfile": "main.tftest.hcl",
  2918  					"test_interrupt": map[string]interface{}{
  2919  						"states": map[string]interface{}{
  2920  							"setup_block": []interface{}{
  2921  								map[string]interface{}{
  2922  									"instance": "test_instance.one",
  2923  								},
  2924  								map[string]interface{}{
  2925  									"instance": "test_instance.two",
  2926  								},
  2927  							},
  2928  						},
  2929  					},
  2930  					"type": "test_interrupt",
  2931  				},
  2932  			},
  2933  		},
  2934  		"all_states_with_plan": {
  2935  			states: map[*moduletest.Run]*states.State{
  2936  				&moduletest.Run{Name: "setup_block"}: states.BuildState(func(state *states.SyncState) {
  2937  					state.SetResourceInstanceCurrent(
  2938  						addrs.AbsResourceInstance{
  2939  							Module: addrs.RootModuleInstance,
  2940  							Resource: addrs.ResourceInstance{
  2941  								Resource: addrs.Resource{
  2942  									Mode: addrs.ManagedResourceMode,
  2943  									Type: "test_instance",
  2944  									Name: "setup_one",
  2945  								},
  2946  							},
  2947  						},
  2948  						&states.ResourceInstanceObjectSrc{},
  2949  						addrs.AbsProviderConfig{})
  2950  
  2951  					state.SetResourceInstanceCurrent(
  2952  						addrs.AbsResourceInstance{
  2953  							Module: addrs.RootModuleInstance,
  2954  							Resource: addrs.ResourceInstance{
  2955  								Resource: addrs.Resource{
  2956  									Mode: addrs.ManagedResourceMode,
  2957  									Type: "test_instance",
  2958  									Name: "setup_two",
  2959  								},
  2960  							},
  2961  						},
  2962  						&states.ResourceInstanceObjectSrc{},
  2963  						addrs.AbsProviderConfig{})
  2964  				}),
  2965  				nil: states.BuildState(func(state *states.SyncState) {
  2966  					state.SetResourceInstanceCurrent(
  2967  						addrs.AbsResourceInstance{
  2968  							Module: addrs.RootModuleInstance,
  2969  							Resource: addrs.ResourceInstance{
  2970  								Resource: addrs.Resource{
  2971  									Mode: addrs.ManagedResourceMode,
  2972  									Type: "test_instance",
  2973  									Name: "one",
  2974  								},
  2975  							},
  2976  						},
  2977  						&states.ResourceInstanceObjectSrc{},
  2978  						addrs.AbsProviderConfig{})
  2979  
  2980  					state.SetResourceInstanceCurrent(
  2981  						addrs.AbsResourceInstance{
  2982  							Module: addrs.RootModuleInstance,
  2983  							Resource: addrs.ResourceInstance{
  2984  								Resource: addrs.Resource{
  2985  									Mode: addrs.ManagedResourceMode,
  2986  									Type: "test_instance",
  2987  									Name: "two",
  2988  								},
  2989  							},
  2990  						},
  2991  						&states.ResourceInstanceObjectSrc{},
  2992  						addrs.AbsProviderConfig{})
  2993  				}),
  2994  			},
  2995  			changes: []*plans.ResourceInstanceChangeSrc{
  2996  				{
  2997  					Addr: addrs.AbsResourceInstance{
  2998  						Module: addrs.RootModuleInstance,
  2999  						Resource: addrs.ResourceInstance{
  3000  							Resource: addrs.Resource{
  3001  								Mode: addrs.ManagedResourceMode,
  3002  								Type: "test_instance",
  3003  								Name: "new_one",
  3004  							},
  3005  						},
  3006  					},
  3007  					ChangeSrc: plans.ChangeSrc{
  3008  						Action: plans.Create,
  3009  					},
  3010  				},
  3011  				{
  3012  					Addr: addrs.AbsResourceInstance{
  3013  						Module: addrs.RootModuleInstance,
  3014  						Resource: addrs.ResourceInstance{
  3015  							Resource: addrs.Resource{
  3016  								Mode: addrs.ManagedResourceMode,
  3017  								Type: "test_instance",
  3018  								Name: "new_two",
  3019  							},
  3020  						},
  3021  					},
  3022  					ChangeSrc: plans.ChangeSrc{
  3023  						Action: plans.Create,
  3024  					},
  3025  				},
  3026  			},
  3027  			want: []map[string]interface{}{
  3028  				{
  3029  					"@level":    "error",
  3030  					"@message":  "Terraform was interrupted during test execution, and may not have performed the expected cleanup operations.",
  3031  					"@module":   "terraform.ui",
  3032  					"@testfile": "main.tftest.hcl",
  3033  					"test_interrupt": map[string]interface{}{
  3034  						"state": []interface{}{
  3035  							map[string]interface{}{
  3036  								"instance": "test_instance.one",
  3037  							},
  3038  							map[string]interface{}{
  3039  								"instance": "test_instance.two",
  3040  							},
  3041  						},
  3042  						"states": map[string]interface{}{
  3043  							"setup_block": []interface{}{
  3044  								map[string]interface{}{
  3045  									"instance": "test_instance.setup_one",
  3046  								},
  3047  								map[string]interface{}{
  3048  									"instance": "test_instance.setup_two",
  3049  								},
  3050  							},
  3051  						},
  3052  						"planned": []interface{}{
  3053  							"test_instance.new_one",
  3054  							"test_instance.new_two",
  3055  						},
  3056  					},
  3057  					"type": "test_interrupt",
  3058  				},
  3059  			},
  3060  		},
  3061  	}
  3062  	for name, tc := range tcs {
  3063  		t.Run(name, func(t *testing.T) {
  3064  			streams, done := terminal.StreamsForTesting(t)
  3065  			view := NewTest(arguments.ViewJSON, NewView(streams))
  3066  
  3067  			file := &moduletest.File{Name: "main.tftest.hcl"}
  3068  			run := &moduletest.Run{Name: "run_block"}
  3069  
  3070  			view.FatalInterruptSummary(run, file, tc.states, tc.changes)
  3071  			testJSONViewOutputEquals(t, done(t).All(), tc.want)
  3072  		})
  3073  	}
  3074  }
  3075  
  3076  func dynamicValue(t *testing.T, value cty.Value, typ cty.Type) plans.DynamicValue {
  3077  	d, err := plans.NewDynamicValue(value, typ)
  3078  	if err != nil {
  3079  		t.Fatalf("failed to create dynamic value: %s", err)
  3080  	}
  3081  	return d
  3082  }