github.com/hashicorp/terraform-plugin-sdk@v1.17.2/helper/resource/testing_new_test.go (about)

     1  package resource
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/go-test/deep"
    10  	tfjson "github.com/hashicorp/terraform-json"
    11  	"github.com/hashicorp/terraform-plugin-sdk/terraform"
    12  )
    13  
    14  func TestShimState(t *testing.T) {
    15  	type expectedError struct {
    16  		Prefix string
    17  	}
    18  
    19  	testCases := []struct {
    20  		Name          string
    21  		RawState      string
    22  		ExpectedState *terraform.State
    23  		ExpectedErr   *expectedError
    24  	}{
    25  		{
    26  			"empty",
    27  			`{
    28    "format_version": "0.1"
    29  }`,
    30  			&terraform.State{
    31  				Version: 3,
    32  				Modules: []*terraform.ModuleState{
    33  					{
    34  						Path:         []string{"root"},
    35  						Outputs:      map[string]*terraform.OutputState{},
    36  						Resources:    map[string]*terraform.ResourceState{},
    37  						Dependencies: []string{},
    38  					},
    39  				},
    40  			},
    41  			nil,
    42  		},
    43  		{
    44  			"simple outputs",
    45  			`{
    46    "format_version": "0.1",
    47    "terraform_version": "0.12.18",
    48    "values": {
    49      "outputs": {
    50        "bool": {
    51          "sensitive": false,
    52          "value": true
    53        },
    54        "int": {
    55          "sensitive": false,
    56          "value": 42
    57        },
    58        "float": {
    59          "sensitive": false,
    60          "value": 1.4
    61        },
    62        "string": {
    63          "sensitive": false,
    64          "value": "test"
    65        }
    66      },
    67      "root_module": {}
    68    }
    69  }`,
    70  			&terraform.State{
    71  				Version:   3,
    72  				TFVersion: "0.12.18",
    73  				Modules: []*terraform.ModuleState{
    74  					{
    75  						Path: []string{"root"},
    76  						Outputs: map[string]*terraform.OutputState{
    77  							"bool": {
    78  								Type:      "string",
    79  								Value:     "true",
    80  								Sensitive: false,
    81  							},
    82  							"int": {
    83  								Type:      "string",
    84  								Value:     "42",
    85  								Sensitive: false,
    86  							},
    87  							"float": {
    88  								Type:      "string",
    89  								Value:     "1.4",
    90  								Sensitive: false,
    91  							},
    92  							"string": {
    93  								Type:      "string",
    94  								Value:     "test",
    95  								Sensitive: false,
    96  							},
    97  						},
    98  						Resources:    map[string]*terraform.ResourceState{},
    99  						Dependencies: []string{},
   100  					},
   101  				},
   102  			},
   103  			nil,
   104  		},
   105  		{
   106  			"complex outputs",
   107  			`{
   108    "format_version": "0.1",
   109    "terraform_version": "0.12.18",
   110    "values": {
   111      "outputs": {
   112        "empty_list": {
   113          "sensitive": false,
   114          "value": []
   115        },
   116        "list_of_strings": {
   117          "sensitive": false,
   118          "value": ["first", "second", "third"]
   119        },
   120        "map_of_strings": {
   121          "sensitive": false,
   122          "value": {
   123          	"hello": "world",
   124          	"foo": "bar"
   125          }
   126        },
   127        "list_of_int": {
   128          "sensitive": false,
   129          "value": [1, 4, 9]
   130        },
   131        "list_of_float": {
   132          "sensitive": false,
   133          "value": [1.2, 4.2, 9.8]
   134        },
   135        "list_of_bool": {
   136          "sensitive": false,
   137          "value": [true, false, true]
   138        }
   139      },
   140      "root_module": {}
   141    }
   142  }`,
   143  			&terraform.State{
   144  				Version:   3,
   145  				TFVersion: "0.12.18",
   146  				Modules: []*terraform.ModuleState{
   147  					{
   148  						Path: []string{"root"},
   149  						Outputs: map[string]*terraform.OutputState{
   150  							"empty_list": {
   151  								Type:      "list",
   152  								Value:     []interface{}{},
   153  								Sensitive: false,
   154  							},
   155  							"list_of_strings": {
   156  								Type: "list",
   157  								Value: []interface{}{
   158  									"first", "second", "third",
   159  								},
   160  								Sensitive: false,
   161  							},
   162  							"map_of_strings": {
   163  								Type: "map",
   164  								Value: map[string]interface{}{
   165  									"hello": "world",
   166  									"foo":   "bar",
   167  								},
   168  								Sensitive: false,
   169  							},
   170  							"list_of_int": {
   171  								Type: "list",
   172  								Value: []interface{}{
   173  									json.Number("1"),
   174  									json.Number("4"),
   175  									json.Number("9"),
   176  								},
   177  								Sensitive: false,
   178  							},
   179  							"list_of_float": {
   180  								Type: "list",
   181  								Value: []interface{}{
   182  									json.Number("1.2"),
   183  									json.Number("4.2"),
   184  									json.Number("9.8"),
   185  								},
   186  								Sensitive: false,
   187  							},
   188  							"list_of_bool": {
   189  								Type: "list",
   190  								Value: []interface{}{
   191  									true, false, true,
   192  								},
   193  								Sensitive: false,
   194  							},
   195  						},
   196  						Resources:    map[string]*terraform.ResourceState{},
   197  						Dependencies: []string{},
   198  					},
   199  				},
   200  			},
   201  			nil,
   202  		},
   203  		{
   204  			"output with slice of slices",
   205  			`{
   206    "format_version": "0.1",
   207    "terraform_version": "0.12.18",
   208    "values": {
   209      "outputs": {
   210        "list_of_lists": {
   211          "sensitive": false,
   212          "value": [
   213            ["one", "two"],
   214            ["blue", "green", "red"]
   215          ]
   216        }
   217      },
   218      "root_module": {}
   219    }
   220  }`,
   221  			&terraform.State{
   222  				Version:   3,
   223  				TFVersion: "0.12.18",
   224  				Modules: []*terraform.ModuleState{
   225  					{
   226  						Path: []string{"root"},
   227  						Outputs: map[string]*terraform.OutputState{
   228  							"list_of_lists": {
   229  								Type: "list",
   230  								Value: []interface{}{
   231  									[]interface{}{"one", "two"},
   232  									[]interface{}{"blue", "green", "red"},
   233  								},
   234  								Sensitive: false,
   235  							},
   236  						},
   237  						Resources:    map[string]*terraform.ResourceState{},
   238  						Dependencies: []string{},
   239  					},
   240  				},
   241  			},
   242  			nil,
   243  		},
   244  		{
   245  			"output with slice of maps",
   246  			`{
   247    "format_version": "0.1",
   248    "terraform_version": "0.12.18",
   249    "values": {
   250      "outputs": {
   251        "list_of_maps": {
   252          "sensitive": false,
   253          "value": [
   254            {
   255              "rule": "allow",
   256              "port": 443,
   257              "allow_bool": true
   258            },
   259            {
   260              "rule": "deny",
   261              "port": 80,
   262              "allow_bool": false
   263            }
   264          ]
   265        }
   266      },
   267      "root_module": {}
   268    }
   269  }`,
   270  			&terraform.State{
   271  				Version:   3,
   272  				TFVersion: "0.12.18",
   273  				Modules: []*terraform.ModuleState{
   274  					{
   275  						Path: []string{"root"},
   276  						Outputs: map[string]*terraform.OutputState{
   277  							"list_of_maps": {
   278  								Type: "list",
   279  								Value: []interface{}{
   280  									map[string]interface{}{
   281  										"allow_bool": true,
   282  										"port":       json.Number("443"),
   283  										"rule":       "allow",
   284  									},
   285  									map[string]interface{}{
   286  										"allow_bool": false,
   287  										"port":       json.Number("80"),
   288  										"rule":       "deny",
   289  									},
   290  								},
   291  								Sensitive: false,
   292  							},
   293  						},
   294  						Resources:    map[string]*terraform.ResourceState{},
   295  						Dependencies: []string{},
   296  					},
   297  				},
   298  			},
   299  			nil,
   300  		},
   301  		{
   302  			"output with nested map",
   303  			`{
   304    "format_version": "0.1",
   305    "terraform_version": "0.12.18",
   306    "values": {
   307      "outputs": {
   308        "map_of_maps": {
   309          "sensitive": false,
   310          "value": {
   311          	"hello": {
   312          	  "whole": "world"
   313          	},
   314          	"foo": "bar"
   315          }
   316        }
   317      },
   318      "root_module": {}
   319    }
   320  }`,
   321  			&terraform.State{
   322  				Version:   3,
   323  				TFVersion: "0.12.18",
   324  				Modules: []*terraform.ModuleState{
   325  					{
   326  						Path: []string{"root"},
   327  						Outputs: map[string]*terraform.OutputState{
   328  							"map_of_maps": {
   329  								Type: "map",
   330  								Value: map[string]interface{}{
   331  									"hello": map[string]interface{}{
   332  										"whole": "world",
   333  									},
   334  									"foo": "bar",
   335  								},
   336  								Sensitive: false,
   337  							},
   338  						},
   339  						Resources:    map[string]*terraform.ResourceState{},
   340  						Dependencies: []string{},
   341  					},
   342  				},
   343  			},
   344  			nil,
   345  		},
   346  		{
   347  			"invalid address",
   348  			`{
   349    "format_version": "0.1",
   350    "values": {
   351      "root_module": {
   352        "address": "blah"
   353      }
   354    }
   355  }`,
   356  			nil,
   357  			&expectedError{Prefix: "Invalid module instance address"},
   358  		},
   359  		{
   360  			"resource with primitive attributes",
   361  			`{
   362    "format_version": "0.1",
   363    "terraform_version": "0.12.18",
   364    "values": {
   365      "outputs": {},
   366      "root_module": {
   367        "resources": [
   368          {
   369            "address": "cloud_vpc.main",
   370            "mode": "managed",
   371            "type": "cloud_vpc",
   372            "name": "main",
   373            "provider_name": "cloud",
   374            "schema_version": 1,
   375            "values": {
   376            	"id": "123999",
   377              "string_field": "hello world",
   378              "bool_field_1": false,
   379              "bool_field_2": true,
   380              "null_field": null,
   381              "empty_string": "",
   382              "number_field": 42
   383            }
   384          }
   385        ]
   386      }
   387    }
   388  }`,
   389  			&terraform.State{
   390  				Version:   3,
   391  				TFVersion: "0.12.18",
   392  				Modules: []*terraform.ModuleState{
   393  					{
   394  						Path:    []string{"root"},
   395  						Outputs: map[string]*terraform.OutputState{},
   396  						Resources: map[string]*terraform.ResourceState{
   397  							"cloud_vpc.main": {
   398  								Type:     "cloud_vpc",
   399  								Provider: "cloud",
   400  								Primary: &terraform.InstanceState{
   401  									ID: "123999",
   402  									Meta: map[string]interface{}{
   403  										"schema_version": 1,
   404  									},
   405  									Attributes: map[string]string{
   406  										"%":  "7",
   407  										"id": "123999",
   408  
   409  										"bool_field_2": "true",
   410  										"string_field": "hello world",
   411  										"bool_field_1": "false",
   412  										"empty_string": "",
   413  										"number_field": "42",
   414  									},
   415  								},
   416  							},
   417  						},
   418  						Dependencies: []string{},
   419  					},
   420  				},
   421  			},
   422  			nil,
   423  		},
   424  		{
   425  			"resource with nested slice",
   426  			`{
   427    "format_version": "0.1",
   428    "terraform_version": "0.12.18",
   429    "values": {
   430      "outputs": {},
   431      "root_module": {
   432        "resources": [
   433          {
   434            "address": "cloud_vpc.main",
   435            "mode": "managed",
   436            "type": "cloud_vpc",
   437            "name": "main",
   438            "provider_name": "cloud",
   439            "schema_version": 1,
   440            "values": {
   441            	"id": "123999",
   442              "list_of_lists": [
   443                ["one", "two", "three"],
   444                ["red", "green", "blue"],
   445                ["black", "white"]
   446              ],
   447              "list_of_maps": [
   448                {
   449                  "action": "allow",
   450                  "port": 443,
   451                  "allow_bool": true
   452                },
   453                {
   454                  "action": "deny",
   455                  "port": 80,
   456                  "allow_bool": false
   457                }
   458              ]
   459            }
   460          }
   461        ]
   462      }
   463    }
   464  }`,
   465  			&terraform.State{
   466  				Version:   3,
   467  				TFVersion: "0.12.18",
   468  				Modules: []*terraform.ModuleState{
   469  					{
   470  						Path:    []string{"root"},
   471  						Outputs: map[string]*terraform.OutputState{},
   472  						Resources: map[string]*terraform.ResourceState{
   473  							"cloud_vpc.main": {
   474  								Type:     "cloud_vpc",
   475  								Provider: "cloud",
   476  								Primary: &terraform.InstanceState{
   477  									ID: "123999",
   478  									Meta: map[string]interface{}{
   479  										"schema_version": 1,
   480  									},
   481  									Attributes: map[string]string{
   482  										"%":  "3",
   483  										"id": "123999",
   484  
   485  										"list_of_lists.#":   "3",
   486  										"list_of_lists.0.#": "3",
   487  										"list_of_lists.0.0": "one",
   488  										"list_of_lists.0.1": "two",
   489  										"list_of_lists.0.2": "three",
   490  										"list_of_lists.1.#": "3",
   491  										"list_of_lists.1.0": "red",
   492  										"list_of_lists.1.1": "green",
   493  										"list_of_lists.1.2": "blue",
   494  										"list_of_lists.2.#": "2",
   495  										"list_of_lists.2.0": "black",
   496  										"list_of_lists.2.1": "white",
   497  
   498  										"list_of_maps.#":            "2",
   499  										"list_of_maps.0.%":          "3",
   500  										"list_of_maps.0.action":     "allow",
   501  										"list_of_maps.0.allow_bool": "true",
   502  										"list_of_maps.0.port":       "443",
   503  										"list_of_maps.1.%":          "3",
   504  										"list_of_maps.1.action":     "deny",
   505  										"list_of_maps.1.allow_bool": "false",
   506  										"list_of_maps.1.port":       "80",
   507  									},
   508  								},
   509  							},
   510  						},
   511  						Dependencies: []string{},
   512  					},
   513  				},
   514  			},
   515  			nil,
   516  		},
   517  		{
   518  			"resource with nested map",
   519  			`{
   520    "format_version": "0.1",
   521    "terraform_version": "0.12.18",
   522    "values": {
   523      "outputs": {},
   524      "root_module": {
   525        "resources": [
   526          {
   527            "address": "cloud_vpc.main",
   528            "mode": "managed",
   529            "type": "cloud_vpc",
   530            "name": "main",
   531            "provider_name": "cloud",
   532            "schema_version": 1,
   533            "values": {
   534            	"id": "123999",
   535              "map_of_maps": {
   536                "parent": {
   537                  "inner": "value"
   538                },
   539                "second": {
   540                  "inner2": "value2"
   541                }
   542              },
   543              "map_of_lists": {
   544                "parent": {
   545                  "inner": ["one", "two"]
   546                },
   547                "second": {
   548                  "inner2": [1, 4, 9]
   549                }
   550              },
   551              "map_of_list_of_maps": {
   552                "parent": [
   553                  {
   554                    "action": "allow",
   555                    "port": 443,
   556                    "allow_bool": true
   557                  },
   558                  {
   559                    "action": "deny",
   560                    "port": 80,
   561                    "allow_bool": false
   562                  }
   563                ]
   564              }
   565            }
   566          }
   567        ]
   568      }
   569    }
   570  }`,
   571  			&terraform.State{
   572  				Version:   3,
   573  				TFVersion: "0.12.18",
   574  				Modules: []*terraform.ModuleState{
   575  					{
   576  						Path:    []string{"root"},
   577  						Outputs: map[string]*terraform.OutputState{},
   578  						Resources: map[string]*terraform.ResourceState{
   579  							"cloud_vpc.main": {
   580  								Type:     "cloud_vpc",
   581  								Provider: "cloud",
   582  								Primary: &terraform.InstanceState{
   583  									ID: "123999",
   584  									Meta: map[string]interface{}{
   585  										"schema_version": 1,
   586  									},
   587  									Attributes: map[string]string{
   588  										"%":  "4",
   589  										"id": "123999",
   590  
   591  										"map_of_maps.%":             "2",
   592  										"map_of_maps.parent.%":      "1",
   593  										"map_of_maps.parent.inner":  "value",
   594  										"map_of_maps.second.%":      "1",
   595  										"map_of_maps.second.inner2": "value2",
   596  
   597  										"map_of_lists.%":               "2",
   598  										"map_of_lists.parent.%":        "1",
   599  										"map_of_lists.parent.inner.#":  "2",
   600  										"map_of_lists.parent.inner.0":  "one",
   601  										"map_of_lists.parent.inner.1":  "two",
   602  										"map_of_lists.second.%":        "1",
   603  										"map_of_lists.second.inner2.#": "3",
   604  										"map_of_lists.second.inner2.0": "1",
   605  										"map_of_lists.second.inner2.1": "4",
   606  										"map_of_lists.second.inner2.2": "9",
   607  
   608  										"map_of_list_of_maps.%":                   "1",
   609  										"map_of_list_of_maps.parent.#":            "2",
   610  										"map_of_list_of_maps.parent.0.%":          "3",
   611  										"map_of_list_of_maps.parent.0.action":     "allow",
   612  										"map_of_list_of_maps.parent.0.allow_bool": "true",
   613  										"map_of_list_of_maps.parent.0.port":       "443",
   614  										"map_of_list_of_maps.parent.1.%":          "3",
   615  										"map_of_list_of_maps.parent.1.action":     "deny",
   616  										"map_of_list_of_maps.parent.1.allow_bool": "false",
   617  										"map_of_list_of_maps.parent.1.port":       "80",
   618  									},
   619  								},
   620  							},
   621  						},
   622  						Dependencies: []string{},
   623  					},
   624  				},
   625  			},
   626  			nil,
   627  		},
   628  		{
   629  			"data source",
   630  			`{
   631    "format_version": "0.1",
   632    "terraform_version": "0.12.18",
   633    "values": {
   634      "outputs": {},
   635      "root_module": {
   636        "resources": [
   637          {
   638            "address": "data.cloud_vpc.main",
   639            "mode": "data",
   640            "type": "cloud_vpc",
   641            "name": "main",
   642            "provider_name": "cloud",
   643            "schema_version": 0,
   644            "values": {
   645            	"id": "123999",
   646              "string_field": "hello world",
   647              "bool_field_1": false,
   648              "bool_field_2": true,
   649              "null_field": null,
   650              "empty_string": "",
   651              "number_field": 42
   652            }
   653          }
   654        ]
   655      }
   656    }
   657  }`,
   658  			&terraform.State{
   659  				Version:   3,
   660  				TFVersion: "0.12.18",
   661  				Modules: []*terraform.ModuleState{
   662  					{
   663  						Path:    []string{"root"},
   664  						Outputs: map[string]*terraform.OutputState{},
   665  						Resources: map[string]*terraform.ResourceState{
   666  							"data.cloud_vpc.main": {
   667  								Type:     "cloud_vpc",
   668  								Provider: "cloud",
   669  								Primary: &terraform.InstanceState{
   670  									ID: "123999",
   671  									Meta: map[string]interface{}{
   672  										"schema_version": 0,
   673  									},
   674  									Attributes: map[string]string{
   675  										"%":  "7",
   676  										"id": "123999",
   677  
   678  										"bool_field_2": "true",
   679  										"string_field": "hello world",
   680  										"bool_field_1": "false",
   681  										"empty_string": "",
   682  										"number_field": "42",
   683  									},
   684  								},
   685  							},
   686  						},
   687  						Dependencies: []string{},
   688  					},
   689  				},
   690  			},
   691  			nil,
   692  		},
   693  		{
   694  			"resource with complex attributes",
   695  			`{
   696    "format_version": "0.1",
   697    "terraform_version": "0.12.18",
   698    "values": {
   699      "outputs": {},
   700      "root_module": {
   701        "resources": [
   702          {
   703            "address": "cloud_vpc.main",
   704            "mode": "managed",
   705            "type": "cloud_vpc",
   706            "name": "main",
   707            "provider_name": "cloud",
   708            "schema_version": 1,
   709            "values": {
   710            	"id": "123999",
   711              "map_field": {
   712                "key": "val",
   713                "foo": "bar"
   714              },
   715              "list_of_string": ["first", "second"],
   716              "list_of_numbers": [1,2,3,4],
   717              "list_of_bool": [true, false, true]
   718            }
   719          }
   720        ]
   721      }
   722    }
   723  }`,
   724  			&terraform.State{
   725  				Version:   3,
   726  				TFVersion: "0.12.18",
   727  				Modules: []*terraform.ModuleState{
   728  					{
   729  						Path:    []string{"root"},
   730  						Outputs: map[string]*terraform.OutputState{},
   731  						Resources: map[string]*terraform.ResourceState{
   732  							"cloud_vpc.main": {
   733  								Type:     "cloud_vpc",
   734  								Provider: "cloud",
   735  								Primary: &terraform.InstanceState{
   736  									ID: "123999",
   737  									Meta: map[string]interface{}{
   738  										"schema_version": 1,
   739  									},
   740  									Attributes: map[string]string{
   741  										"%":  "5",
   742  										"id": "123999",
   743  
   744  										"map_field.%":   "2",
   745  										"map_field.key": "val",
   746  										"map_field.foo": "bar",
   747  
   748  										"list_of_string.#": "2",
   749  										"list_of_string.0": "first",
   750  										"list_of_string.1": "second",
   751  
   752  										"list_of_numbers.#": "4",
   753  										"list_of_numbers.0": "1",
   754  										"list_of_numbers.1": "2",
   755  										"list_of_numbers.2": "3",
   756  										"list_of_numbers.3": "4",
   757  
   758  										"list_of_bool.#": "3",
   759  										"list_of_bool.0": "true",
   760  										"list_of_bool.1": "false",
   761  										"list_of_bool.2": "true",
   762  									},
   763  								},
   764  							},
   765  						},
   766  						Dependencies: []string{},
   767  					},
   768  				},
   769  			},
   770  			nil,
   771  		},
   772  		{
   773  			"indexed resource",
   774  			`{
   775    "format_version": "0.1",
   776    "terraform_version": "0.12.18",
   777    "values": {
   778      "outputs": {},
   779      "root_module": {
   780        "resources": [
   781          {
   782            "address": "cloud_vpc.main",
   783            "index": 0,
   784            "mode": "managed",
   785            "type": "cloud_vpc",
   786            "name": "main",
   787            "provider_name": "cloud",
   788            "schema_version": 1,
   789            "values": {
   790            	"id": "11111"
   791            }
   792          },
   793          {
   794            "address": "cloud_vpc.main",
   795            "index": 1,
   796            "mode": "managed",
   797            "type": "cloud_vpc",
   798            "name": "main",
   799            "provider_name": "cloud",
   800            "schema_version": 1,
   801            "values": {
   802            	"id": "22222"
   803            }
   804          }
   805        ]
   806      }
   807    }
   808  }`,
   809  			&terraform.State{
   810  				Version:   3,
   811  				TFVersion: "0.12.18",
   812  				Modules: []*terraform.ModuleState{
   813  					{
   814  						Path:    []string{"root"},
   815  						Outputs: map[string]*terraform.OutputState{},
   816  						Resources: map[string]*terraform.ResourceState{
   817  							"cloud_vpc.main.0": {
   818  								Type:     "cloud_vpc",
   819  								Provider: "cloud",
   820  								Primary: &terraform.InstanceState{
   821  									ID: "11111",
   822  									Meta: map[string]interface{}{
   823  										"schema_version": 1,
   824  									},
   825  									Attributes: map[string]string{
   826  										"%":  "1",
   827  										"id": "11111",
   828  									},
   829  								},
   830  							},
   831  							"cloud_vpc.main.1": {
   832  								Type:     "cloud_vpc",
   833  								Provider: "cloud",
   834  								Primary: &terraform.InstanceState{
   835  									ID: "22222",
   836  									Meta: map[string]interface{}{
   837  										"schema_version": 1,
   838  									},
   839  									Attributes: map[string]string{
   840  										"%":  "1",
   841  										"id": "22222",
   842  									},
   843  								},
   844  							},
   845  						},
   846  						Dependencies: []string{},
   847  					},
   848  				},
   849  			},
   850  			nil,
   851  		},
   852  		{
   853  			"indexed data source",
   854  			`{
   855    "format_version": "0.1",
   856    "terraform_version": "0.12.18",
   857    "values": {
   858      "outputs": {},
   859      "root_module": {
   860        "resources": [
   861          {
   862            "address": "data.cloud_vpc.main",
   863            "index": 0,
   864            "mode": "data",
   865            "type": "cloud_vpc",
   866            "name": "main",
   867            "provider_name": "cloud",
   868            "schema_version": 0,
   869            "values": {
   870            	"id": "11111"
   871            }
   872          },
   873          {
   874            "address": "data.cloud_vpc.main",
   875            "index": 1,
   876            "mode": "data",
   877            "type": "cloud_vpc",
   878            "name": "main",
   879            "provider_name": "cloud",
   880            "schema_version": 0,
   881            "values": {
   882            	"id": "22222"
   883            }
   884          }
   885        ]
   886      }
   887    }
   888  }`,
   889  			&terraform.State{
   890  				Version:   3,
   891  				TFVersion: "0.12.18",
   892  				Modules: []*terraform.ModuleState{
   893  					{
   894  						Path:    []string{"root"},
   895  						Outputs: map[string]*terraform.OutputState{},
   896  						Resources: map[string]*terraform.ResourceState{
   897  							"data.cloud_vpc.main.0": {
   898  								Type:     "cloud_vpc",
   899  								Provider: "cloud",
   900  								Primary: &terraform.InstanceState{
   901  									ID: "11111",
   902  									Meta: map[string]interface{}{
   903  										"schema_version": 0,
   904  									},
   905  									Attributes: map[string]string{
   906  										"%":  "1",
   907  										"id": "11111",
   908  									},
   909  								},
   910  							},
   911  							"data.cloud_vpc.main.1": {
   912  								Type:     "cloud_vpc",
   913  								Provider: "cloud",
   914  								Primary: &terraform.InstanceState{
   915  									ID: "22222",
   916  									Meta: map[string]interface{}{
   917  										"schema_version": 0,
   918  									},
   919  									Attributes: map[string]string{
   920  										"%":  "1",
   921  										"id": "22222",
   922  									},
   923  								},
   924  							},
   925  						},
   926  						Dependencies: []string{},
   927  					},
   928  				},
   929  			},
   930  			nil,
   931  		},
   932  		{
   933  			"for_each",
   934  			`{
   935    "format_version": "0.1",
   936    "terraform_version": "0.12.18",
   937    "values": {
   938      "outputs": {},
   939      "root_module": {
   940        "resources": [
   941          {
   942            "address": "cloud_vpc.main",
   943            "index": "one",
   944            "mode": "managed",
   945            "type": "cloud_vpc",
   946            "name": "main",
   947            "provider_name": "cloud",
   948            "schema_version": 1,
   949            "values": {
   950            	"id": "11111"
   951            }
   952          },
   953          {
   954            "address": "cloud_vpc.main",
   955            "index": "two",
   956            "mode": "managed",
   957            "type": "cloud_vpc",
   958            "name": "main",
   959            "provider_name": "cloud",
   960            "schema_version": 1,
   961            "values": {
   962            	"id": "22222"
   963            }
   964          }
   965        ]
   966      }
   967    }
   968  }`,
   969  			nil,
   970  			&expectedError{Prefix: "unexpected index type (string)"},
   971  		},
   972  		{
   973  			"depends on",
   974  			`{
   975    "format_version": "0.1",
   976    "terraform_version": "0.12.18",
   977    "values": {
   978      "outputs": {},
   979      "root_module": {
   980        "resources": [
   981          {
   982            "address": "cloud_vpc.primary",
   983            "mode": "managed",
   984            "type": "cloud_vpc",
   985            "name": "primary",
   986            "provider_name": "cloud",
   987            "values": {
   988            	"id": "11111"
   989            }
   990          },
   991          {
   992            "address": "cloud_vpc.secondary",
   993            "mode": "managed",
   994            "type": "cloud_vpc",
   995            "name": "secondary",
   996            "provider_name": "cloud",
   997            "values": {
   998            	"id": "22222"
   999            },
  1000            "depends_on": [
  1001              "cloud_vpc.primary"
  1002            ]
  1003          }
  1004        ]
  1005      }
  1006    }
  1007  }`,
  1008  			&terraform.State{
  1009  				Version:   3,
  1010  				TFVersion: "0.12.18",
  1011  				Modules: []*terraform.ModuleState{
  1012  					{
  1013  						Path:    []string{"root"},
  1014  						Outputs: map[string]*terraform.OutputState{},
  1015  						Resources: map[string]*terraform.ResourceState{
  1016  							"cloud_vpc.primary": {
  1017  								Type:     "cloud_vpc",
  1018  								Provider: "cloud",
  1019  								Primary: &terraform.InstanceState{
  1020  									ID: "11111",
  1021  									Meta: map[string]interface{}{
  1022  										"schema_version": 0,
  1023  									},
  1024  									Attributes: map[string]string{
  1025  										"%":  "1",
  1026  										"id": "11111",
  1027  									},
  1028  								},
  1029  							},
  1030  							"cloud_vpc.secondary": {
  1031  								Type:     "cloud_vpc",
  1032  								Provider: "cloud",
  1033  								Primary: &terraform.InstanceState{
  1034  									ID: "22222",
  1035  									Meta: map[string]interface{}{
  1036  										"schema_version": 0,
  1037  									},
  1038  									Attributes: map[string]string{
  1039  										"%":  "1",
  1040  										"id": "22222",
  1041  									},
  1042  								},
  1043  								Dependencies: []string{
  1044  									"cloud_vpc.primary",
  1045  								},
  1046  							},
  1047  						},
  1048  						Dependencies: []string{},
  1049  					},
  1050  				},
  1051  			},
  1052  			nil,
  1053  		},
  1054  		{
  1055  			"child modules",
  1056  			`{
  1057    "format_version": "0.1",
  1058    "terraform_version": "0.12.18",
  1059    "values": {
  1060      "root_module": {
  1061        "child_modules": [
  1062          {
  1063            "resources": [
  1064              {
  1065                "address": "cloud_vpc.primary",
  1066                "mode": "managed",
  1067                "type": "cloud_vpc",
  1068                "name": "primary",
  1069                "provider_name": "cloud",
  1070                "values": {
  1071                  "id": "11111"
  1072                }
  1073              }
  1074            ]
  1075          }
  1076        ]
  1077      }
  1078    }
  1079  }`,
  1080  			nil,
  1081  			&expectedError{Prefix: "Modules are not supported."},
  1082  		},
  1083  	}
  1084  
  1085  	for i, tc := range testCases {
  1086  		t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
  1087  			var rawState tfjson.State
  1088  			rawState.UseJSONNumber(true)
  1089  
  1090  			err := unmarshalJSON([]byte(tc.RawState), &rawState)
  1091  			if err != nil {
  1092  				t.Fatal(err)
  1093  			}
  1094  
  1095  			shimmedState, err := shimStateFromJson(&rawState)
  1096  			if tc.ExpectedErr != nil {
  1097  				if err == nil {
  1098  					t.Fatalf("Expected error with prefix: %q\nGot no error.",
  1099  						tc.ExpectedErr.Prefix)
  1100  				}
  1101  				if strings.HasPrefix(err.Error(), tc.ExpectedErr.Prefix) {
  1102  					return
  1103  				}
  1104  				t.Fatalf("Error mismatch.\nExpected prefix: %q\nGot: %q\n",
  1105  					tc.ExpectedErr.Prefix, err.Error())
  1106  			}
  1107  			if err != nil {
  1108  				t.Fatal(err)
  1109  			}
  1110  
  1111  			// Lineage is randomly generated, so we wipe it to make comparing easier
  1112  			shimmedState.Lineage = ""
  1113  
  1114  			if diff := deep.Equal(tc.ExpectedState, shimmedState); diff != nil {
  1115  				t.Fatalf("state mismatch:\n%s", strings.Join(diff, "\n"))
  1116  			}
  1117  		})
  1118  	}
  1119  }