github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/helper/schema/resource_data_test.go (about)

     1  package schema
     2  
     3  import (
     4  	"math"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/hashicorp/terraform/terraform"
     9  )
    10  
    11  func TestResourceDataGet(t *testing.T) {
    12  	cases := []struct {
    13  		Schema map[string]*Schema
    14  		State  *terraform.InstanceState
    15  		Diff   *terraform.InstanceDiff
    16  		Key    string
    17  		Value  interface{}
    18  	}{
    19  		// #0
    20  		{
    21  			Schema: map[string]*Schema{
    22  				"availability_zone": &Schema{
    23  					Type:     TypeString,
    24  					Optional: true,
    25  					Computed: true,
    26  					ForceNew: true,
    27  				},
    28  			},
    29  
    30  			State: nil,
    31  
    32  			Diff: &terraform.InstanceDiff{
    33  				Attributes: map[string]*terraform.ResourceAttrDiff{
    34  					"availability_zone": &terraform.ResourceAttrDiff{
    35  						Old:         "foo",
    36  						New:         "bar",
    37  						NewComputed: true,
    38  					},
    39  				},
    40  			},
    41  
    42  			Key:   "availability_zone",
    43  			Value: "",
    44  		},
    45  
    46  		// #1
    47  		{
    48  			Schema: map[string]*Schema{
    49  				"availability_zone": &Schema{
    50  					Type:     TypeString,
    51  					Optional: true,
    52  					Computed: true,
    53  					ForceNew: true,
    54  				},
    55  			},
    56  
    57  			State: nil,
    58  
    59  			Diff: &terraform.InstanceDiff{
    60  				Attributes: map[string]*terraform.ResourceAttrDiff{
    61  					"availability_zone": &terraform.ResourceAttrDiff{
    62  						Old:         "",
    63  						New:         "foo",
    64  						RequiresNew: true,
    65  					},
    66  				},
    67  			},
    68  
    69  			Key: "availability_zone",
    70  
    71  			Value: "foo",
    72  		},
    73  
    74  		// #2
    75  		{
    76  			Schema: map[string]*Schema{
    77  				"availability_zone": &Schema{
    78  					Type:     TypeString,
    79  					Optional: true,
    80  					Computed: true,
    81  					ForceNew: true,
    82  				},
    83  			},
    84  
    85  			State: nil,
    86  
    87  			Diff: &terraform.InstanceDiff{
    88  				Attributes: map[string]*terraform.ResourceAttrDiff{
    89  					"availability_zone": &terraform.ResourceAttrDiff{
    90  						Old:      "",
    91  						New:      "foo!",
    92  						NewExtra: "foo",
    93  					},
    94  				},
    95  			},
    96  
    97  			Key:   "availability_zone",
    98  			Value: "foo",
    99  		},
   100  
   101  		// #3
   102  		{
   103  			Schema: map[string]*Schema{
   104  				"availability_zone": &Schema{
   105  					Type:     TypeString,
   106  					Optional: true,
   107  					Computed: true,
   108  					ForceNew: true,
   109  				},
   110  			},
   111  
   112  			State: &terraform.InstanceState{
   113  				Attributes: map[string]string{
   114  					"availability_zone": "bar",
   115  				},
   116  			},
   117  
   118  			Diff: nil,
   119  
   120  			Key: "availability_zone",
   121  
   122  			Value: "bar",
   123  		},
   124  
   125  		// #4
   126  		{
   127  			Schema: map[string]*Schema{
   128  				"availability_zone": &Schema{
   129  					Type:     TypeString,
   130  					Optional: true,
   131  					Computed: true,
   132  					ForceNew: true,
   133  				},
   134  			},
   135  
   136  			State: &terraform.InstanceState{
   137  				Attributes: map[string]string{
   138  					"availability_zone": "foo",
   139  				},
   140  			},
   141  
   142  			Diff: &terraform.InstanceDiff{
   143  				Attributes: map[string]*terraform.ResourceAttrDiff{
   144  					"availability_zone": &terraform.ResourceAttrDiff{
   145  						Old:         "foo",
   146  						New:         "bar",
   147  						NewComputed: true,
   148  					},
   149  				},
   150  			},
   151  
   152  			Key:   "availability_zone",
   153  			Value: "",
   154  		},
   155  
   156  		// #5
   157  		{
   158  			Schema: map[string]*Schema{
   159  				"port": &Schema{
   160  					Type:     TypeInt,
   161  					Optional: true,
   162  					Computed: true,
   163  					ForceNew: true,
   164  				},
   165  			},
   166  
   167  			State: &terraform.InstanceState{
   168  				Attributes: map[string]string{
   169  					"port": "80",
   170  				},
   171  			},
   172  
   173  			Diff: nil,
   174  
   175  			Key: "port",
   176  
   177  			Value: 80,
   178  		},
   179  
   180  		// #6
   181  		{
   182  			Schema: map[string]*Schema{
   183  				"ports": &Schema{
   184  					Type:     TypeList,
   185  					Required: true,
   186  					Elem:     &Schema{Type: TypeInt},
   187  				},
   188  			},
   189  
   190  			State: &terraform.InstanceState{
   191  				Attributes: map[string]string{
   192  					"ports.#": "3",
   193  					"ports.0": "1",
   194  					"ports.1": "2",
   195  					"ports.2": "5",
   196  				},
   197  			},
   198  
   199  			Key: "ports.1",
   200  
   201  			Value: 2,
   202  		},
   203  
   204  		// #7
   205  		{
   206  			Schema: map[string]*Schema{
   207  				"ports": &Schema{
   208  					Type:     TypeList,
   209  					Required: true,
   210  					Elem:     &Schema{Type: TypeInt},
   211  				},
   212  			},
   213  
   214  			State: &terraform.InstanceState{
   215  				Attributes: map[string]string{
   216  					"ports.#": "3",
   217  					"ports.0": "1",
   218  					"ports.1": "2",
   219  					"ports.2": "5",
   220  				},
   221  			},
   222  
   223  			Key: "ports.#",
   224  
   225  			Value: 3,
   226  		},
   227  
   228  		// #8
   229  		{
   230  			Schema: map[string]*Schema{
   231  				"ports": &Schema{
   232  					Type:     TypeList,
   233  					Required: true,
   234  					Elem:     &Schema{Type: TypeInt},
   235  				},
   236  			},
   237  
   238  			State: nil,
   239  
   240  			Key: "ports.#",
   241  
   242  			Value: 0,
   243  		},
   244  
   245  		// #9
   246  		{
   247  			Schema: map[string]*Schema{
   248  				"ports": &Schema{
   249  					Type:     TypeList,
   250  					Required: true,
   251  					Elem:     &Schema{Type: TypeInt},
   252  				},
   253  			},
   254  
   255  			State: &terraform.InstanceState{
   256  				Attributes: map[string]string{
   257  					"ports.#": "3",
   258  					"ports.0": "1",
   259  					"ports.1": "2",
   260  					"ports.2": "5",
   261  				},
   262  			},
   263  
   264  			Key: "ports",
   265  
   266  			Value: []interface{}{1, 2, 5},
   267  		},
   268  
   269  		// #10
   270  		{
   271  			Schema: map[string]*Schema{
   272  				"ingress": &Schema{
   273  					Type:     TypeList,
   274  					Required: true,
   275  					Elem: &Resource{
   276  						Schema: map[string]*Schema{
   277  							"from": &Schema{
   278  								Type:     TypeInt,
   279  								Required: true,
   280  							},
   281  						},
   282  					},
   283  				},
   284  			},
   285  
   286  			State: nil,
   287  
   288  			Diff: &terraform.InstanceDiff{
   289  				Attributes: map[string]*terraform.ResourceAttrDiff{
   290  					"ingress.#": &terraform.ResourceAttrDiff{
   291  						Old: "",
   292  						New: "1",
   293  					},
   294  					"ingress.0.from": &terraform.ResourceAttrDiff{
   295  						Old: "",
   296  						New: "8080",
   297  					},
   298  				},
   299  			},
   300  
   301  			Key: "ingress.0",
   302  
   303  			Value: map[string]interface{}{
   304  				"from": 8080,
   305  			},
   306  		},
   307  
   308  		// #11
   309  		{
   310  			Schema: map[string]*Schema{
   311  				"ingress": &Schema{
   312  					Type:     TypeList,
   313  					Required: true,
   314  					Elem: &Resource{
   315  						Schema: map[string]*Schema{
   316  							"from": &Schema{
   317  								Type:     TypeInt,
   318  								Required: true,
   319  							},
   320  						},
   321  					},
   322  				},
   323  			},
   324  
   325  			State: nil,
   326  
   327  			Diff: &terraform.InstanceDiff{
   328  				Attributes: map[string]*terraform.ResourceAttrDiff{
   329  					"ingress.#": &terraform.ResourceAttrDiff{
   330  						Old: "",
   331  						New: "1",
   332  					},
   333  					"ingress.0.from": &terraform.ResourceAttrDiff{
   334  						Old: "",
   335  						New: "8080",
   336  					},
   337  				},
   338  			},
   339  
   340  			Key: "ingress",
   341  
   342  			Value: []interface{}{
   343  				map[string]interface{}{
   344  					"from": 8080,
   345  				},
   346  			},
   347  		},
   348  
   349  		// #12 Computed get
   350  		{
   351  			Schema: map[string]*Schema{
   352  				"availability_zone": &Schema{
   353  					Type:     TypeString,
   354  					Computed: true,
   355  				},
   356  			},
   357  
   358  			State: &terraform.InstanceState{
   359  				Attributes: map[string]string{
   360  					"availability_zone": "foo",
   361  				},
   362  			},
   363  
   364  			Key: "availability_zone",
   365  
   366  			Value: "foo",
   367  		},
   368  
   369  		// #13 Full object
   370  		{
   371  			Schema: map[string]*Schema{
   372  				"availability_zone": &Schema{
   373  					Type:     TypeString,
   374  					Optional: true,
   375  					Computed: true,
   376  					ForceNew: true,
   377  				},
   378  			},
   379  
   380  			State: nil,
   381  
   382  			Diff: &terraform.InstanceDiff{
   383  				Attributes: map[string]*terraform.ResourceAttrDiff{
   384  					"availability_zone": &terraform.ResourceAttrDiff{
   385  						Old:         "",
   386  						New:         "foo",
   387  						RequiresNew: true,
   388  					},
   389  				},
   390  			},
   391  
   392  			Key: "",
   393  
   394  			Value: map[string]interface{}{
   395  				"availability_zone": "foo",
   396  			},
   397  		},
   398  
   399  		// #14 List of maps
   400  		{
   401  			Schema: map[string]*Schema{
   402  				"config_vars": &Schema{
   403  					Type:     TypeList,
   404  					Optional: true,
   405  					Computed: true,
   406  					Elem: &Schema{
   407  						Type: TypeMap,
   408  					},
   409  				},
   410  			},
   411  
   412  			State: nil,
   413  
   414  			Diff: &terraform.InstanceDiff{
   415  				Attributes: map[string]*terraform.ResourceAttrDiff{
   416  					"config_vars.#": &terraform.ResourceAttrDiff{
   417  						Old: "0",
   418  						New: "2",
   419  					},
   420  					"config_vars.0.foo": &terraform.ResourceAttrDiff{
   421  						Old: "",
   422  						New: "bar",
   423  					},
   424  					"config_vars.1.bar": &terraform.ResourceAttrDiff{
   425  						Old: "",
   426  						New: "baz",
   427  					},
   428  				},
   429  			},
   430  
   431  			Key: "config_vars",
   432  
   433  			Value: []interface{}{
   434  				map[string]interface{}{
   435  					"foo": "bar",
   436  				},
   437  				map[string]interface{}{
   438  					"bar": "baz",
   439  				},
   440  			},
   441  		},
   442  
   443  		// #15 List of maps in state
   444  		{
   445  			Schema: map[string]*Schema{
   446  				"config_vars": &Schema{
   447  					Type:     TypeList,
   448  					Optional: true,
   449  					Computed: true,
   450  					Elem: &Schema{
   451  						Type: TypeMap,
   452  					},
   453  				},
   454  			},
   455  
   456  			State: &terraform.InstanceState{
   457  				Attributes: map[string]string{
   458  					"config_vars.#":     "2",
   459  					"config_vars.0.foo": "baz",
   460  					"config_vars.1.bar": "bar",
   461  				},
   462  			},
   463  
   464  			Diff: nil,
   465  
   466  			Key: "config_vars",
   467  
   468  			Value: []interface{}{
   469  				map[string]interface{}{
   470  					"foo": "baz",
   471  				},
   472  				map[string]interface{}{
   473  					"bar": "bar",
   474  				},
   475  			},
   476  		},
   477  
   478  		// #16 List of maps with removal in diff
   479  		{
   480  			Schema: map[string]*Schema{
   481  				"config_vars": &Schema{
   482  					Type:     TypeList,
   483  					Optional: true,
   484  					Computed: true,
   485  					Elem: &Schema{
   486  						Type: TypeMap,
   487  					},
   488  				},
   489  			},
   490  
   491  			State: &terraform.InstanceState{
   492  				Attributes: map[string]string{
   493  					"config_vars.#":     "1",
   494  					"config_vars.0.FOO": "bar",
   495  				},
   496  			},
   497  
   498  			Diff: &terraform.InstanceDiff{
   499  				Attributes: map[string]*terraform.ResourceAttrDiff{
   500  					"config_vars.#": &terraform.ResourceAttrDiff{
   501  						Old: "1",
   502  						New: "0",
   503  					},
   504  					"config_vars.0.FOO": &terraform.ResourceAttrDiff{
   505  						Old:        "bar",
   506  						NewRemoved: true,
   507  					},
   508  				},
   509  			},
   510  
   511  			Key: "config_vars",
   512  
   513  			Value: []interface{}{},
   514  		},
   515  
   516  		// #17 Sets
   517  		{
   518  			Schema: map[string]*Schema{
   519  				"ports": &Schema{
   520  					Type:     TypeSet,
   521  					Optional: true,
   522  					Computed: true,
   523  					Elem:     &Schema{Type: TypeInt},
   524  					Set: func(a interface{}) int {
   525  						return a.(int)
   526  					},
   527  				},
   528  			},
   529  
   530  			State: &terraform.InstanceState{
   531  				Attributes: map[string]string{
   532  					"ports.#":  "1",
   533  					"ports.80": "80",
   534  				},
   535  			},
   536  
   537  			Diff: nil,
   538  
   539  			Key: "ports",
   540  
   541  			Value: []interface{}{80},
   542  		},
   543  
   544  		// #18
   545  		{
   546  			Schema: map[string]*Schema{
   547  				"data": &Schema{
   548  					Type:     TypeSet,
   549  					Optional: true,
   550  					Elem: &Resource{
   551  						Schema: map[string]*Schema{
   552  							"index": &Schema{
   553  								Type:     TypeInt,
   554  								Required: true,
   555  							},
   556  
   557  							"value": &Schema{
   558  								Type:     TypeString,
   559  								Required: true,
   560  							},
   561  						},
   562  					},
   563  					Set: func(a interface{}) int {
   564  						m := a.(map[string]interface{})
   565  						return m["index"].(int)
   566  					},
   567  				},
   568  			},
   569  
   570  			State: &terraform.InstanceState{
   571  				Attributes: map[string]string{
   572  					"data.#":        "1",
   573  					"data.10.index": "10",
   574  					"data.10.value": "50",
   575  				},
   576  			},
   577  
   578  			Diff: &terraform.InstanceDiff{
   579  				Attributes: map[string]*terraform.ResourceAttrDiff{
   580  					"data.10.value": &terraform.ResourceAttrDiff{
   581  						Old: "50",
   582  						New: "80",
   583  					},
   584  				},
   585  			},
   586  
   587  			Key: "data",
   588  
   589  			Value: []interface{}{
   590  				map[string]interface{}{
   591  					"index": 10,
   592  					"value": "80",
   593  				},
   594  			},
   595  		},
   596  
   597  		// #19 Empty Set
   598  		{
   599  			Schema: map[string]*Schema{
   600  				"ports": &Schema{
   601  					Type:     TypeSet,
   602  					Optional: true,
   603  					Computed: true,
   604  					Elem:     &Schema{Type: TypeInt},
   605  					Set: func(a interface{}) int {
   606  						return a.(int)
   607  					},
   608  				},
   609  			},
   610  
   611  			State: nil,
   612  
   613  			Diff: nil,
   614  
   615  			Key: "ports",
   616  
   617  			Value: []interface{}{},
   618  		},
   619  
   620  		// #20 Float zero
   621  		{
   622  			Schema: map[string]*Schema{
   623  				"ratio": &Schema{
   624  					Type:     TypeFloat,
   625  					Optional: true,
   626  					Computed: true,
   627  				},
   628  			},
   629  
   630  			State: nil,
   631  
   632  			Diff: nil,
   633  
   634  			Key: "ratio",
   635  
   636  			Value: 0.0,
   637  		},
   638  
   639  		// #21 Float given
   640  		{
   641  			Schema: map[string]*Schema{
   642  				"ratio": &Schema{
   643  					Type:     TypeFloat,
   644  					Optional: true,
   645  					Computed: true,
   646  				},
   647  			},
   648  
   649  			State: &terraform.InstanceState{
   650  				Attributes: map[string]string{
   651  					"ratio": "0.5",
   652  				},
   653  			},
   654  
   655  			Diff: nil,
   656  
   657  			Key: "ratio",
   658  
   659  			Value: 0.5,
   660  		},
   661  
   662  		// #22 Float diff
   663  		{
   664  			Schema: map[string]*Schema{
   665  				"ratio": &Schema{
   666  					Type:     TypeFloat,
   667  					Optional: true,
   668  					Computed: true,
   669  				},
   670  			},
   671  
   672  			State: &terraform.InstanceState{
   673  				Attributes: map[string]string{
   674  					"ratio": "-0.5",
   675  				},
   676  			},
   677  
   678  			Diff: &terraform.InstanceDiff{
   679  				Attributes: map[string]*terraform.ResourceAttrDiff{
   680  					"ratio": &terraform.ResourceAttrDiff{
   681  						Old: "-0.5",
   682  						New: "33.0",
   683  					},
   684  				},
   685  			},
   686  
   687  			Key: "ratio",
   688  
   689  			Value: 33.0,
   690  		},
   691  	}
   692  
   693  	for i, tc := range cases {
   694  		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
   695  		if err != nil {
   696  			t.Fatalf("err: %s", err)
   697  		}
   698  
   699  		v := d.Get(tc.Key)
   700  		if s, ok := v.(*Set); ok {
   701  			v = s.List()
   702  		}
   703  
   704  		if !reflect.DeepEqual(v, tc.Value) {
   705  			t.Fatalf("Bad: %d\n\n%#v\n\nExpected: %#v", i, v, tc.Value)
   706  		}
   707  	}
   708  }
   709  
   710  func TestResourceDataGetChange(t *testing.T) {
   711  	cases := []struct {
   712  		Schema   map[string]*Schema
   713  		State    *terraform.InstanceState
   714  		Diff     *terraform.InstanceDiff
   715  		Key      string
   716  		OldValue interface{}
   717  		NewValue interface{}
   718  	}{
   719  		{
   720  			Schema: map[string]*Schema{
   721  				"availability_zone": &Schema{
   722  					Type:     TypeString,
   723  					Optional: true,
   724  					Computed: true,
   725  					ForceNew: true,
   726  				},
   727  			},
   728  
   729  			State: nil,
   730  
   731  			Diff: &terraform.InstanceDiff{
   732  				Attributes: map[string]*terraform.ResourceAttrDiff{
   733  					"availability_zone": &terraform.ResourceAttrDiff{
   734  						Old:         "",
   735  						New:         "foo",
   736  						RequiresNew: true,
   737  					},
   738  				},
   739  			},
   740  
   741  			Key: "availability_zone",
   742  
   743  			OldValue: "",
   744  			NewValue: "foo",
   745  		},
   746  
   747  		{
   748  			Schema: map[string]*Schema{
   749  				"availability_zone": &Schema{
   750  					Type:     TypeString,
   751  					Optional: true,
   752  					Computed: true,
   753  					ForceNew: true,
   754  				},
   755  			},
   756  
   757  			State: &terraform.InstanceState{
   758  				Attributes: map[string]string{
   759  					"availability_zone": "foo",
   760  				},
   761  			},
   762  
   763  			Diff: &terraform.InstanceDiff{
   764  				Attributes: map[string]*terraform.ResourceAttrDiff{
   765  					"availability_zone": &terraform.ResourceAttrDiff{
   766  						Old:         "",
   767  						New:         "foo",
   768  						RequiresNew: true,
   769  					},
   770  				},
   771  			},
   772  
   773  			Key: "availability_zone",
   774  
   775  			OldValue: "foo",
   776  			NewValue: "foo",
   777  		},
   778  	}
   779  
   780  	for i, tc := range cases {
   781  		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
   782  		if err != nil {
   783  			t.Fatalf("err: %s", err)
   784  		}
   785  
   786  		o, n := d.GetChange(tc.Key)
   787  		if !reflect.DeepEqual(o, tc.OldValue) {
   788  			t.Fatalf("Old Bad: %d\n\n%#v", i, o)
   789  		}
   790  		if !reflect.DeepEqual(n, tc.NewValue) {
   791  			t.Fatalf("New Bad: %d\n\n%#v", i, n)
   792  		}
   793  	}
   794  }
   795  
   796  func TestResourceDataGetOk(t *testing.T) {
   797  	cases := []struct {
   798  		Schema map[string]*Schema
   799  		State  *terraform.InstanceState
   800  		Diff   *terraform.InstanceDiff
   801  		Key    string
   802  		Value  interface{}
   803  		Ok     bool
   804  	}{
   805  		/*
   806  		 * Primitives
   807  		 */
   808  		{
   809  			Schema: map[string]*Schema{
   810  				"availability_zone": &Schema{
   811  					Type:     TypeString,
   812  					Optional: true,
   813  					Computed: true,
   814  					ForceNew: true,
   815  				},
   816  			},
   817  
   818  			State: nil,
   819  
   820  			Diff: &terraform.InstanceDiff{
   821  				Attributes: map[string]*terraform.ResourceAttrDiff{
   822  					"availability_zone": &terraform.ResourceAttrDiff{
   823  						Old: "",
   824  						New: "",
   825  					},
   826  				},
   827  			},
   828  
   829  			Key:   "availability_zone",
   830  			Value: "",
   831  			Ok:    false,
   832  		},
   833  
   834  		{
   835  			Schema: map[string]*Schema{
   836  				"availability_zone": &Schema{
   837  					Type:     TypeString,
   838  					Optional: true,
   839  					Computed: true,
   840  					ForceNew: true,
   841  				},
   842  			},
   843  
   844  			State: nil,
   845  
   846  			Diff: &terraform.InstanceDiff{
   847  				Attributes: map[string]*terraform.ResourceAttrDiff{
   848  					"availability_zone": &terraform.ResourceAttrDiff{
   849  						Old:         "",
   850  						New:         "",
   851  						NewComputed: true,
   852  					},
   853  				},
   854  			},
   855  
   856  			Key:   "availability_zone",
   857  			Value: "",
   858  			Ok:    false,
   859  		},
   860  
   861  		{
   862  			Schema: map[string]*Schema{
   863  				"availability_zone": &Schema{
   864  					Type:     TypeString,
   865  					Optional: true,
   866  					Computed: true,
   867  					ForceNew: true,
   868  				},
   869  			},
   870  
   871  			State: nil,
   872  
   873  			Diff: nil,
   874  
   875  			Key:   "availability_zone",
   876  			Value: "",
   877  			Ok:    false,
   878  		},
   879  
   880  		/*
   881  		 * Lists
   882  		 */
   883  
   884  		{
   885  			Schema: map[string]*Schema{
   886  				"ports": &Schema{
   887  					Type:     TypeList,
   888  					Optional: true,
   889  					Elem:     &Schema{Type: TypeInt},
   890  				},
   891  			},
   892  
   893  			State: nil,
   894  
   895  			Diff: nil,
   896  
   897  			Key:   "ports",
   898  			Value: []interface{}{},
   899  			Ok:    false,
   900  		},
   901  
   902  		/*
   903  		 * Map
   904  		 */
   905  
   906  		{
   907  			Schema: map[string]*Schema{
   908  				"ports": &Schema{
   909  					Type:     TypeMap,
   910  					Optional: true,
   911  				},
   912  			},
   913  
   914  			State: nil,
   915  
   916  			Diff: nil,
   917  
   918  			Key:   "ports",
   919  			Value: map[string]interface{}{},
   920  			Ok:    false,
   921  		},
   922  
   923  		/*
   924  		 * Set
   925  		 */
   926  
   927  		{
   928  			Schema: map[string]*Schema{
   929  				"ports": &Schema{
   930  					Type:     TypeSet,
   931  					Optional: true,
   932  					Elem:     &Schema{Type: TypeInt},
   933  					Set:      func(a interface{}) int { return a.(int) },
   934  				},
   935  			},
   936  
   937  			State: nil,
   938  
   939  			Diff: nil,
   940  
   941  			Key:   "ports",
   942  			Value: []interface{}{},
   943  			Ok:    false,
   944  		},
   945  
   946  		{
   947  			Schema: map[string]*Schema{
   948  				"ports": &Schema{
   949  					Type:     TypeSet,
   950  					Optional: true,
   951  					Elem:     &Schema{Type: TypeInt},
   952  					Set:      func(a interface{}) int { return a.(int) },
   953  				},
   954  			},
   955  
   956  			State: nil,
   957  
   958  			Diff: nil,
   959  
   960  			Key:   "ports.0",
   961  			Value: 0,
   962  			Ok:    false,
   963  		},
   964  
   965  		{
   966  			Schema: map[string]*Schema{
   967  				"ports": &Schema{
   968  					Type:     TypeSet,
   969  					Optional: true,
   970  					Elem:     &Schema{Type: TypeInt},
   971  					Set:      func(a interface{}) int { return a.(int) },
   972  				},
   973  			},
   974  
   975  			State: nil,
   976  
   977  			Diff: &terraform.InstanceDiff{
   978  				Attributes: map[string]*terraform.ResourceAttrDiff{
   979  					"ports.#": &terraform.ResourceAttrDiff{
   980  						Old: "0",
   981  						New: "0",
   982  					},
   983  				},
   984  			},
   985  
   986  			Key:   "ports",
   987  			Value: []interface{}{},
   988  			Ok:    false,
   989  		},
   990  	}
   991  
   992  	for i, tc := range cases {
   993  		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
   994  		if err != nil {
   995  			t.Fatalf("err: %s", err)
   996  		}
   997  
   998  		v, ok := d.GetOk(tc.Key)
   999  		if s, ok := v.(*Set); ok {
  1000  			v = s.List()
  1001  		}
  1002  
  1003  		if !reflect.DeepEqual(v, tc.Value) {
  1004  			t.Fatalf("Bad: %d\n\n%#v", i, v)
  1005  		}
  1006  		if ok != tc.Ok {
  1007  			t.Fatalf("Bad: %d\n\n%#v", i, ok)
  1008  		}
  1009  	}
  1010  }
  1011  
  1012  func TestResourceDataHasChange(t *testing.T) {
  1013  	cases := []struct {
  1014  		Schema map[string]*Schema
  1015  		State  *terraform.InstanceState
  1016  		Diff   *terraform.InstanceDiff
  1017  		Key    string
  1018  		Change bool
  1019  	}{
  1020  		{
  1021  			Schema: map[string]*Schema{
  1022  				"availability_zone": &Schema{
  1023  					Type:     TypeString,
  1024  					Optional: true,
  1025  					Computed: true,
  1026  					ForceNew: true,
  1027  				},
  1028  			},
  1029  
  1030  			State: nil,
  1031  
  1032  			Diff: &terraform.InstanceDiff{
  1033  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1034  					"availability_zone": &terraform.ResourceAttrDiff{
  1035  						Old:         "",
  1036  						New:         "foo",
  1037  						RequiresNew: true,
  1038  					},
  1039  				},
  1040  			},
  1041  
  1042  			Key: "availability_zone",
  1043  
  1044  			Change: true,
  1045  		},
  1046  
  1047  		{
  1048  			Schema: map[string]*Schema{
  1049  				"availability_zone": &Schema{
  1050  					Type:     TypeString,
  1051  					Optional: true,
  1052  					Computed: true,
  1053  					ForceNew: true,
  1054  				},
  1055  			},
  1056  
  1057  			State: &terraform.InstanceState{
  1058  				Attributes: map[string]string{
  1059  					"availability_zone": "foo",
  1060  				},
  1061  			},
  1062  
  1063  			Diff: &terraform.InstanceDiff{
  1064  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1065  					"availability_zone": &terraform.ResourceAttrDiff{
  1066  						Old:         "",
  1067  						New:         "foo",
  1068  						RequiresNew: true,
  1069  					},
  1070  				},
  1071  			},
  1072  
  1073  			Key: "availability_zone",
  1074  
  1075  			Change: false,
  1076  		},
  1077  
  1078  		{
  1079  			Schema: map[string]*Schema{
  1080  				"tags": &Schema{
  1081  					Type:     TypeMap,
  1082  					Optional: true,
  1083  					Computed: true,
  1084  				},
  1085  			},
  1086  
  1087  			State: nil,
  1088  
  1089  			Diff: &terraform.InstanceDiff{
  1090  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1091  					"tags.Name": &terraform.ResourceAttrDiff{
  1092  						Old: "foo",
  1093  						New: "foo",
  1094  					},
  1095  				},
  1096  			},
  1097  
  1098  			Key: "tags",
  1099  
  1100  			Change: true,
  1101  		},
  1102  
  1103  		{
  1104  			Schema: map[string]*Schema{
  1105  				"ports": &Schema{
  1106  					Type:     TypeSet,
  1107  					Optional: true,
  1108  					Elem:     &Schema{Type: TypeInt},
  1109  					Set:      func(a interface{}) int { return a.(int) },
  1110  				},
  1111  			},
  1112  
  1113  			State: &terraform.InstanceState{
  1114  				Attributes: map[string]string{
  1115  					"ports.#":  "1",
  1116  					"ports.80": "80",
  1117  				},
  1118  			},
  1119  
  1120  			Diff: &terraform.InstanceDiff{
  1121  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1122  					"ports.#": &terraform.ResourceAttrDiff{
  1123  						Old: "1",
  1124  						New: "0",
  1125  					},
  1126  				},
  1127  			},
  1128  
  1129  			Key: "ports",
  1130  
  1131  			Change: true,
  1132  		},
  1133  
  1134  		// https://github.com/hashicorp/terraform/issues/927
  1135  		{
  1136  			Schema: map[string]*Schema{
  1137  				"ports": &Schema{
  1138  					Type:     TypeSet,
  1139  					Optional: true,
  1140  					Elem:     &Schema{Type: TypeInt},
  1141  					Set:      func(a interface{}) int { return a.(int) },
  1142  				},
  1143  			},
  1144  
  1145  			State: &terraform.InstanceState{
  1146  				Attributes: map[string]string{
  1147  					"ports.#":  "1",
  1148  					"ports.80": "80",
  1149  				},
  1150  			},
  1151  
  1152  			Diff: &terraform.InstanceDiff{
  1153  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1154  					"tags.foo": &terraform.ResourceAttrDiff{
  1155  						Old: "",
  1156  						New: "bar",
  1157  					},
  1158  				},
  1159  			},
  1160  
  1161  			Key: "ports",
  1162  
  1163  			Change: false,
  1164  		},
  1165  	}
  1166  
  1167  	for i, tc := range cases {
  1168  		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
  1169  		if err != nil {
  1170  			t.Fatalf("err: %s", err)
  1171  		}
  1172  
  1173  		actual := d.HasChange(tc.Key)
  1174  		if actual != tc.Change {
  1175  			t.Fatalf("Bad: %d %#v", i, actual)
  1176  		}
  1177  	}
  1178  }
  1179  
  1180  func TestResourceDataSet(t *testing.T) {
  1181  	cases := []struct {
  1182  		Schema   map[string]*Schema
  1183  		State    *terraform.InstanceState
  1184  		Diff     *terraform.InstanceDiff
  1185  		Key      string
  1186  		Value    interface{}
  1187  		Err      bool
  1188  		GetKey   string
  1189  		GetValue interface{}
  1190  
  1191  		// GetPreProcess can be set to munge the return value before being
  1192  		// compared to GetValue
  1193  		GetPreProcess func(interface{}) interface{}
  1194  	}{
  1195  		// #0: Basic good
  1196  		{
  1197  			Schema: map[string]*Schema{
  1198  				"availability_zone": &Schema{
  1199  					Type:     TypeString,
  1200  					Optional: true,
  1201  					Computed: true,
  1202  					ForceNew: true,
  1203  				},
  1204  			},
  1205  
  1206  			State: nil,
  1207  
  1208  			Diff: nil,
  1209  
  1210  			Key:   "availability_zone",
  1211  			Value: "foo",
  1212  
  1213  			GetKey:   "availability_zone",
  1214  			GetValue: "foo",
  1215  		},
  1216  
  1217  		// #1: Basic int
  1218  		{
  1219  			Schema: map[string]*Schema{
  1220  				"port": &Schema{
  1221  					Type:     TypeInt,
  1222  					Optional: true,
  1223  					Computed: true,
  1224  					ForceNew: true,
  1225  				},
  1226  			},
  1227  
  1228  			State: nil,
  1229  
  1230  			Diff: nil,
  1231  
  1232  			Key:   "port",
  1233  			Value: 80,
  1234  
  1235  			GetKey:   "port",
  1236  			GetValue: 80,
  1237  		},
  1238  
  1239  		// #2: Basic bool
  1240  		{
  1241  			Schema: map[string]*Schema{
  1242  				"vpc": &Schema{
  1243  					Type:     TypeBool,
  1244  					Optional: true,
  1245  				},
  1246  			},
  1247  
  1248  			State: nil,
  1249  
  1250  			Diff: nil,
  1251  
  1252  			Key:   "vpc",
  1253  			Value: true,
  1254  
  1255  			GetKey:   "vpc",
  1256  			GetValue: true,
  1257  		},
  1258  
  1259  		// #3
  1260  		{
  1261  			Schema: map[string]*Schema{
  1262  				"vpc": &Schema{
  1263  					Type:     TypeBool,
  1264  					Optional: true,
  1265  				},
  1266  			},
  1267  
  1268  			State: nil,
  1269  
  1270  			Diff: nil,
  1271  
  1272  			Key:   "vpc",
  1273  			Value: false,
  1274  
  1275  			GetKey:   "vpc",
  1276  			GetValue: false,
  1277  		},
  1278  
  1279  		// #4: Invalid type
  1280  		{
  1281  			Schema: map[string]*Schema{
  1282  				"availability_zone": &Schema{
  1283  					Type:     TypeString,
  1284  					Optional: true,
  1285  					Computed: true,
  1286  					ForceNew: true,
  1287  				},
  1288  			},
  1289  
  1290  			State: nil,
  1291  
  1292  			Diff: nil,
  1293  
  1294  			Key:   "availability_zone",
  1295  			Value: 80,
  1296  			Err:   true,
  1297  
  1298  			GetKey:   "availability_zone",
  1299  			GetValue: "",
  1300  		},
  1301  
  1302  		// #5: List of primitives, set list
  1303  		{
  1304  			Schema: map[string]*Schema{
  1305  				"ports": &Schema{
  1306  					Type:     TypeList,
  1307  					Computed: true,
  1308  					Elem:     &Schema{Type: TypeInt},
  1309  				},
  1310  			},
  1311  
  1312  			State: nil,
  1313  
  1314  			Diff: nil,
  1315  
  1316  			Key:   "ports",
  1317  			Value: []int{1, 2, 5},
  1318  
  1319  			GetKey:   "ports",
  1320  			GetValue: []interface{}{1, 2, 5},
  1321  		},
  1322  
  1323  		// #6: List of primitives, set list with error
  1324  		{
  1325  			Schema: map[string]*Schema{
  1326  				"ports": &Schema{
  1327  					Type:     TypeList,
  1328  					Computed: true,
  1329  					Elem:     &Schema{Type: TypeInt},
  1330  				},
  1331  			},
  1332  
  1333  			State: nil,
  1334  
  1335  			Diff: nil,
  1336  
  1337  			Key:   "ports",
  1338  			Value: []interface{}{1, "NOPE", 5},
  1339  			Err:   true,
  1340  
  1341  			GetKey:   "ports",
  1342  			GetValue: []interface{}{},
  1343  		},
  1344  
  1345  		// #7: Set a list of maps
  1346  		{
  1347  			Schema: map[string]*Schema{
  1348  				"config_vars": &Schema{
  1349  					Type:     TypeList,
  1350  					Optional: true,
  1351  					Computed: true,
  1352  					Elem: &Schema{
  1353  						Type: TypeMap,
  1354  					},
  1355  				},
  1356  			},
  1357  
  1358  			State: nil,
  1359  
  1360  			Diff: nil,
  1361  
  1362  			Key: "config_vars",
  1363  			Value: []interface{}{
  1364  				map[string]interface{}{
  1365  					"foo": "bar",
  1366  				},
  1367  				map[string]interface{}{
  1368  					"bar": "baz",
  1369  				},
  1370  			},
  1371  			Err: false,
  1372  
  1373  			GetKey: "config_vars",
  1374  			GetValue: []interface{}{
  1375  				map[string]interface{}{
  1376  					"foo": "bar",
  1377  				},
  1378  				map[string]interface{}{
  1379  					"bar": "baz",
  1380  				},
  1381  			},
  1382  		},
  1383  
  1384  		// #8: Set, with list
  1385  		{
  1386  			Schema: map[string]*Schema{
  1387  				"ports": &Schema{
  1388  					Type:     TypeSet,
  1389  					Optional: true,
  1390  					Computed: true,
  1391  					Elem:     &Schema{Type: TypeInt},
  1392  					Set: func(a interface{}) int {
  1393  						return a.(int)
  1394  					},
  1395  				},
  1396  			},
  1397  
  1398  			State: &terraform.InstanceState{
  1399  				Attributes: map[string]string{
  1400  					"ports.#": "3",
  1401  					"ports.0": "100",
  1402  					"ports.1": "80",
  1403  					"ports.2": "80",
  1404  				},
  1405  			},
  1406  
  1407  			Key:   "ports",
  1408  			Value: []interface{}{100, 125, 125},
  1409  
  1410  			GetKey:   "ports",
  1411  			GetValue: []interface{}{100, 125},
  1412  		},
  1413  
  1414  		// #9: Set, with Set
  1415  		{
  1416  			Schema: map[string]*Schema{
  1417  				"ports": &Schema{
  1418  					Type:     TypeSet,
  1419  					Optional: true,
  1420  					Computed: true,
  1421  					Elem:     &Schema{Type: TypeInt},
  1422  					Set: func(a interface{}) int {
  1423  						return a.(int)
  1424  					},
  1425  				},
  1426  			},
  1427  
  1428  			State: &terraform.InstanceState{
  1429  				Attributes: map[string]string{
  1430  					"ports.#":   "3",
  1431  					"ports.100": "100",
  1432  					"ports.80":  "80",
  1433  					"ports.81":  "81",
  1434  				},
  1435  			},
  1436  
  1437  			Key: "ports",
  1438  			Value: &Set{
  1439  				m: map[int]interface{}{
  1440  					1: 1,
  1441  					2: 2,
  1442  				},
  1443  			},
  1444  
  1445  			GetKey:   "ports",
  1446  			GetValue: []interface{}{1, 2},
  1447  		},
  1448  
  1449  		// #10: Set single item
  1450  		{
  1451  			Schema: map[string]*Schema{
  1452  				"ports": &Schema{
  1453  					Type:     TypeSet,
  1454  					Optional: true,
  1455  					Computed: true,
  1456  					Elem:     &Schema{Type: TypeInt},
  1457  					Set: func(a interface{}) int {
  1458  						return a.(int)
  1459  					},
  1460  				},
  1461  			},
  1462  
  1463  			State: &terraform.InstanceState{
  1464  				Attributes: map[string]string{
  1465  					"ports.#":   "2",
  1466  					"ports.100": "100",
  1467  					"ports.80":  "80",
  1468  				},
  1469  			},
  1470  
  1471  			Key:   "ports.100",
  1472  			Value: 256,
  1473  			Err:   true,
  1474  
  1475  			GetKey:   "ports",
  1476  			GetValue: []interface{}{80, 100},
  1477  		},
  1478  
  1479  		// #11: Set with nested set
  1480  		{
  1481  			Schema: map[string]*Schema{
  1482  				"ports": &Schema{
  1483  					Type: TypeSet,
  1484  					Elem: &Resource{
  1485  						Schema: map[string]*Schema{
  1486  							"port": &Schema{
  1487  								Type: TypeInt,
  1488  							},
  1489  
  1490  							"set": &Schema{
  1491  								Type: TypeSet,
  1492  								Elem: &Schema{Type: TypeInt},
  1493  								Set: func(a interface{}) int {
  1494  									return a.(int)
  1495  								},
  1496  							},
  1497  						},
  1498  					},
  1499  					Set: func(a interface{}) int {
  1500  						return a.(map[string]interface{})["port"].(int)
  1501  					},
  1502  				},
  1503  			},
  1504  
  1505  			State: nil,
  1506  
  1507  			Key: "ports",
  1508  			Value: []interface{}{
  1509  				map[string]interface{}{
  1510  					"port": 80,
  1511  				},
  1512  			},
  1513  
  1514  			GetKey: "ports",
  1515  			GetValue: []interface{}{
  1516  				map[string]interface{}{
  1517  					"port": 80,
  1518  					"set":  []interface{}{},
  1519  				},
  1520  			},
  1521  
  1522  			GetPreProcess: func(v interface{}) interface{} {
  1523  				if v == nil {
  1524  					return v
  1525  				}
  1526  				s, ok := v.([]interface{})
  1527  				if !ok {
  1528  					return v
  1529  				}
  1530  				for _, v := range s {
  1531  					m, ok := v.(map[string]interface{})
  1532  					if !ok {
  1533  						continue
  1534  					}
  1535  					if m["set"] == nil {
  1536  						continue
  1537  					}
  1538  					if s, ok := m["set"].(*Set); ok {
  1539  						m["set"] = s.List()
  1540  					}
  1541  				}
  1542  
  1543  				return v
  1544  			},
  1545  		},
  1546  
  1547  		// #12: List of floats, set list
  1548  		{
  1549  			Schema: map[string]*Schema{
  1550  				"ratios": &Schema{
  1551  					Type:     TypeList,
  1552  					Computed: true,
  1553  					Elem:     &Schema{Type: TypeFloat},
  1554  				},
  1555  			},
  1556  
  1557  			State: nil,
  1558  
  1559  			Diff: nil,
  1560  
  1561  			Key:   "ratios",
  1562  			Value: []float64{1.0, 2.2, 5.5},
  1563  
  1564  			GetKey:   "ratios",
  1565  			GetValue: []interface{}{1.0, 2.2, 5.5},
  1566  		},
  1567  
  1568  		// #12: Set of floats, set list
  1569  		{
  1570  			Schema: map[string]*Schema{
  1571  				"ratios": &Schema{
  1572  					Type:     TypeSet,
  1573  					Computed: true,
  1574  					Elem:     &Schema{Type: TypeFloat},
  1575  					Set: func(a interface{}) int {
  1576  						return int(math.Float64bits(a.(float64)))
  1577  					},
  1578  				},
  1579  			},
  1580  
  1581  			State: nil,
  1582  
  1583  			Diff: nil,
  1584  
  1585  			Key:   "ratios",
  1586  			Value: []float64{1.0, 2.2, 5.5},
  1587  
  1588  			GetKey:   "ratios",
  1589  			GetValue: []interface{}{1.0, 2.2, 5.5},
  1590  		},
  1591  	}
  1592  
  1593  	for i, tc := range cases {
  1594  		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
  1595  		if err != nil {
  1596  			t.Fatalf("err: %s", err)
  1597  		}
  1598  
  1599  		err = d.Set(tc.Key, tc.Value)
  1600  		if (err != nil) != tc.Err {
  1601  			t.Fatalf("%d err: %s", i, err)
  1602  		}
  1603  
  1604  		v := d.Get(tc.GetKey)
  1605  		if s, ok := v.(*Set); ok {
  1606  			v = s.List()
  1607  		}
  1608  
  1609  		if tc.GetPreProcess != nil {
  1610  			v = tc.GetPreProcess(v)
  1611  		}
  1612  
  1613  		if !reflect.DeepEqual(v, tc.GetValue) {
  1614  			t.Fatalf("Get Bad: %d\n\n%#v", i, v)
  1615  		}
  1616  	}
  1617  }
  1618  
  1619  func TestResourceDataState(t *testing.T) {
  1620  	cases := []struct {
  1621  		Schema  map[string]*Schema
  1622  		State   *terraform.InstanceState
  1623  		Diff    *terraform.InstanceDiff
  1624  		Set     map[string]interface{}
  1625  		Result  *terraform.InstanceState
  1626  		Partial []string
  1627  	}{
  1628  		// #0 Basic primitive in diff
  1629  		{
  1630  			Schema: map[string]*Schema{
  1631  				"availability_zone": &Schema{
  1632  					Type:     TypeString,
  1633  					Optional: true,
  1634  					Computed: true,
  1635  					ForceNew: true,
  1636  				},
  1637  			},
  1638  
  1639  			State: nil,
  1640  
  1641  			Diff: &terraform.InstanceDiff{
  1642  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1643  					"availability_zone": &terraform.ResourceAttrDiff{
  1644  						Old:         "",
  1645  						New:         "foo",
  1646  						RequiresNew: true,
  1647  					},
  1648  				},
  1649  			},
  1650  
  1651  			Result: &terraform.InstanceState{
  1652  				Attributes: map[string]string{
  1653  					"availability_zone": "foo",
  1654  				},
  1655  			},
  1656  		},
  1657  
  1658  		// #1 Basic primitive set override
  1659  		{
  1660  			Schema: map[string]*Schema{
  1661  				"availability_zone": &Schema{
  1662  					Type:     TypeString,
  1663  					Optional: true,
  1664  					Computed: true,
  1665  					ForceNew: true,
  1666  				},
  1667  			},
  1668  
  1669  			State: nil,
  1670  
  1671  			Diff: &terraform.InstanceDiff{
  1672  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1673  					"availability_zone": &terraform.ResourceAttrDiff{
  1674  						Old:         "",
  1675  						New:         "foo",
  1676  						RequiresNew: true,
  1677  					},
  1678  				},
  1679  			},
  1680  
  1681  			Set: map[string]interface{}{
  1682  				"availability_zone": "bar",
  1683  			},
  1684  
  1685  			Result: &terraform.InstanceState{
  1686  				Attributes: map[string]string{
  1687  					"availability_zone": "bar",
  1688  				},
  1689  			},
  1690  		},
  1691  
  1692  		// #2
  1693  		{
  1694  			Schema: map[string]*Schema{
  1695  				"vpc": &Schema{
  1696  					Type:     TypeBool,
  1697  					Optional: true,
  1698  				},
  1699  			},
  1700  
  1701  			State: nil,
  1702  
  1703  			Diff: nil,
  1704  
  1705  			Set: map[string]interface{}{
  1706  				"vpc": true,
  1707  			},
  1708  
  1709  			Result: &terraform.InstanceState{
  1710  				Attributes: map[string]string{
  1711  					"vpc": "true",
  1712  				},
  1713  			},
  1714  		},
  1715  
  1716  		// #3 Basic primitive with StateFunc set
  1717  		{
  1718  			Schema: map[string]*Schema{
  1719  				"availability_zone": &Schema{
  1720  					Type:      TypeString,
  1721  					Optional:  true,
  1722  					Computed:  true,
  1723  					StateFunc: func(interface{}) string { return "" },
  1724  				},
  1725  			},
  1726  
  1727  			State: nil,
  1728  
  1729  			Diff: &terraform.InstanceDiff{
  1730  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1731  					"availability_zone": &terraform.ResourceAttrDiff{
  1732  						Old:      "",
  1733  						New:      "foo",
  1734  						NewExtra: "foo!",
  1735  					},
  1736  				},
  1737  			},
  1738  
  1739  			Result: &terraform.InstanceState{
  1740  				Attributes: map[string]string{
  1741  					"availability_zone": "foo",
  1742  				},
  1743  			},
  1744  		},
  1745  
  1746  		// #4 List
  1747  		{
  1748  			Schema: map[string]*Schema{
  1749  				"ports": &Schema{
  1750  					Type:     TypeList,
  1751  					Required: true,
  1752  					Elem:     &Schema{Type: TypeInt},
  1753  				},
  1754  			},
  1755  
  1756  			State: &terraform.InstanceState{
  1757  				Attributes: map[string]string{
  1758  					"ports.#": "1",
  1759  					"ports.0": "80",
  1760  				},
  1761  			},
  1762  
  1763  			Diff: &terraform.InstanceDiff{
  1764  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1765  					"ports.#": &terraform.ResourceAttrDiff{
  1766  						Old: "1",
  1767  						New: "2",
  1768  					},
  1769  					"ports.1": &terraform.ResourceAttrDiff{
  1770  						Old: "",
  1771  						New: "100",
  1772  					},
  1773  				},
  1774  			},
  1775  
  1776  			Result: &terraform.InstanceState{
  1777  				Attributes: map[string]string{
  1778  					"ports.#": "2",
  1779  					"ports.0": "80",
  1780  					"ports.1": "100",
  1781  				},
  1782  			},
  1783  		},
  1784  
  1785  		// #5 List of resources
  1786  		{
  1787  			Schema: map[string]*Schema{
  1788  				"ingress": &Schema{
  1789  					Type:     TypeList,
  1790  					Required: true,
  1791  					Elem: &Resource{
  1792  						Schema: map[string]*Schema{
  1793  							"from": &Schema{
  1794  								Type:     TypeInt,
  1795  								Required: true,
  1796  							},
  1797  						},
  1798  					},
  1799  				},
  1800  			},
  1801  
  1802  			State: &terraform.InstanceState{
  1803  				Attributes: map[string]string{
  1804  					"ingress.#":      "1",
  1805  					"ingress.0.from": "80",
  1806  				},
  1807  			},
  1808  
  1809  			Diff: &terraform.InstanceDiff{
  1810  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1811  					"ingress.#": &terraform.ResourceAttrDiff{
  1812  						Old: "1",
  1813  						New: "2",
  1814  					},
  1815  					"ingress.0.from": &terraform.ResourceAttrDiff{
  1816  						Old: "80",
  1817  						New: "150",
  1818  					},
  1819  					"ingress.1.from": &terraform.ResourceAttrDiff{
  1820  						Old: "",
  1821  						New: "100",
  1822  					},
  1823  				},
  1824  			},
  1825  
  1826  			Result: &terraform.InstanceState{
  1827  				Attributes: map[string]string{
  1828  					"ingress.#":      "2",
  1829  					"ingress.0.from": "150",
  1830  					"ingress.1.from": "100",
  1831  				},
  1832  			},
  1833  		},
  1834  
  1835  		// #6 List of maps
  1836  		{
  1837  			Schema: map[string]*Schema{
  1838  				"config_vars": &Schema{
  1839  					Type:     TypeList,
  1840  					Optional: true,
  1841  					Computed: true,
  1842  					Elem: &Schema{
  1843  						Type: TypeMap,
  1844  					},
  1845  				},
  1846  			},
  1847  
  1848  			State: &terraform.InstanceState{
  1849  				Attributes: map[string]string{
  1850  					"config_vars.#":     "2",
  1851  					"config_vars.0.#":   "2",
  1852  					"config_vars.0.foo": "bar",
  1853  					"config_vars.0.bar": "bar",
  1854  					"config_vars.1.#":   "1",
  1855  					"config_vars.1.bar": "baz",
  1856  				},
  1857  			},
  1858  
  1859  			Diff: &terraform.InstanceDiff{
  1860  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1861  					"config_vars.0.bar": &terraform.ResourceAttrDiff{
  1862  						NewRemoved: true,
  1863  					},
  1864  				},
  1865  			},
  1866  
  1867  			Set: map[string]interface{}{
  1868  				"config_vars": []map[string]interface{}{
  1869  					map[string]interface{}{
  1870  						"foo": "bar",
  1871  					},
  1872  					map[string]interface{}{
  1873  						"baz": "bang",
  1874  					},
  1875  				},
  1876  			},
  1877  
  1878  			Result: &terraform.InstanceState{
  1879  				Attributes: map[string]string{
  1880  					"config_vars.#":     "2",
  1881  					"config_vars.0.#":   "1",
  1882  					"config_vars.0.foo": "bar",
  1883  					"config_vars.1.#":   "1",
  1884  					"config_vars.1.baz": "bang",
  1885  				},
  1886  			},
  1887  		},
  1888  
  1889  		// #7 List of maps with removal in diff
  1890  		{
  1891  			Schema: map[string]*Schema{
  1892  				"config_vars": &Schema{
  1893  					Type:     TypeList,
  1894  					Optional: true,
  1895  					Computed: true,
  1896  					Elem: &Schema{
  1897  						Type: TypeMap,
  1898  					},
  1899  				},
  1900  			},
  1901  
  1902  			State: &terraform.InstanceState{
  1903  				Attributes: map[string]string{
  1904  					"config_vars.#":     "1",
  1905  					"config_vars.0.FOO": "bar",
  1906  				},
  1907  			},
  1908  
  1909  			Diff: &terraform.InstanceDiff{
  1910  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1911  					"config_vars.#": &terraform.ResourceAttrDiff{
  1912  						Old: "1",
  1913  						New: "0",
  1914  					},
  1915  					"config_vars.0.FOO": &terraform.ResourceAttrDiff{
  1916  						Old:        "bar",
  1917  						NewRemoved: true,
  1918  					},
  1919  				},
  1920  			},
  1921  
  1922  			Result: &terraform.InstanceState{
  1923  				Attributes: map[string]string{
  1924  					"config_vars.#": "0",
  1925  				},
  1926  			},
  1927  		},
  1928  
  1929  		// #8 Basic state with other keys
  1930  		{
  1931  			Schema: map[string]*Schema{
  1932  				"availability_zone": &Schema{
  1933  					Type:     TypeString,
  1934  					Optional: true,
  1935  					Computed: true,
  1936  					ForceNew: true,
  1937  				},
  1938  			},
  1939  
  1940  			State: &terraform.InstanceState{
  1941  				ID: "bar",
  1942  				Attributes: map[string]string{
  1943  					"id": "bar",
  1944  				},
  1945  			},
  1946  
  1947  			Diff: &terraform.InstanceDiff{
  1948  				Attributes: map[string]*terraform.ResourceAttrDiff{
  1949  					"availability_zone": &terraform.ResourceAttrDiff{
  1950  						Old:         "",
  1951  						New:         "foo",
  1952  						RequiresNew: true,
  1953  					},
  1954  				},
  1955  			},
  1956  
  1957  			Result: &terraform.InstanceState{
  1958  				ID: "bar",
  1959  				Attributes: map[string]string{
  1960  					"id":                "bar",
  1961  					"availability_zone": "foo",
  1962  				},
  1963  			},
  1964  		},
  1965  
  1966  		// #9 Sets
  1967  		{
  1968  			Schema: map[string]*Schema{
  1969  				"ports": &Schema{
  1970  					Type:     TypeSet,
  1971  					Optional: true,
  1972  					Computed: true,
  1973  					Elem:     &Schema{Type: TypeInt},
  1974  					Set: func(a interface{}) int {
  1975  						return a.(int)
  1976  					},
  1977  				},
  1978  			},
  1979  
  1980  			State: &terraform.InstanceState{
  1981  				Attributes: map[string]string{
  1982  					"ports.#":   "3",
  1983  					"ports.100": "100",
  1984  					"ports.80":  "80",
  1985  					"ports.81":  "81",
  1986  				},
  1987  			},
  1988  
  1989  			Diff: nil,
  1990  
  1991  			Result: &terraform.InstanceState{
  1992  				Attributes: map[string]string{
  1993  					"ports.#":   "3",
  1994  					"ports.80":  "80",
  1995  					"ports.81":  "81",
  1996  					"ports.100": "100",
  1997  				},
  1998  			},
  1999  		},
  2000  
  2001  		// #10
  2002  		{
  2003  			Schema: map[string]*Schema{
  2004  				"ports": &Schema{
  2005  					Type:     TypeSet,
  2006  					Optional: true,
  2007  					Computed: true,
  2008  					Elem:     &Schema{Type: TypeInt},
  2009  					Set: func(a interface{}) int {
  2010  						return a.(int)
  2011  					},
  2012  				},
  2013  			},
  2014  
  2015  			State: nil,
  2016  
  2017  			Diff: nil,
  2018  
  2019  			Set: map[string]interface{}{
  2020  				"ports": []interface{}{100, 80},
  2021  			},
  2022  
  2023  			Result: &terraform.InstanceState{
  2024  				Attributes: map[string]string{
  2025  					"ports.#":   "2",
  2026  					"ports.80":  "80",
  2027  					"ports.100": "100",
  2028  				},
  2029  			},
  2030  		},
  2031  
  2032  		// #11
  2033  		{
  2034  			Schema: map[string]*Schema{
  2035  				"ports": &Schema{
  2036  					Type:     TypeSet,
  2037  					Optional: true,
  2038  					Computed: true,
  2039  					Elem: &Resource{
  2040  						Schema: map[string]*Schema{
  2041  							"order": &Schema{
  2042  								Type: TypeInt,
  2043  							},
  2044  
  2045  							"a": &Schema{
  2046  								Type: TypeList,
  2047  								Elem: &Schema{Type: TypeInt},
  2048  							},
  2049  
  2050  							"b": &Schema{
  2051  								Type: TypeList,
  2052  								Elem: &Schema{Type: TypeInt},
  2053  							},
  2054  						},
  2055  					},
  2056  					Set: func(a interface{}) int {
  2057  						m := a.(map[string]interface{})
  2058  						return m["order"].(int)
  2059  					},
  2060  				},
  2061  			},
  2062  
  2063  			State: &terraform.InstanceState{
  2064  				Attributes: map[string]string{
  2065  					"ports.#":        "2",
  2066  					"ports.10.order": "10",
  2067  					"ports.10.a.#":   "1",
  2068  					"ports.10.a.0":   "80",
  2069  					"ports.20.order": "20",
  2070  					"ports.20.b.#":   "1",
  2071  					"ports.20.b.0":   "100",
  2072  				},
  2073  			},
  2074  
  2075  			Set: map[string]interface{}{
  2076  				"ports": []interface{}{
  2077  					map[string]interface{}{
  2078  						"order": 20,
  2079  						"b":     []interface{}{100},
  2080  					},
  2081  					map[string]interface{}{
  2082  						"order": 10,
  2083  						"a":     []interface{}{80},
  2084  					},
  2085  				},
  2086  			},
  2087  
  2088  			Result: &terraform.InstanceState{
  2089  				Attributes: map[string]string{
  2090  					"ports.#":        "2",
  2091  					"ports.10.order": "10",
  2092  					"ports.10.a.#":   "1",
  2093  					"ports.10.a.0":   "80",
  2094  					"ports.10.b.#":   "0",
  2095  					"ports.20.order": "20",
  2096  					"ports.20.a.#":   "0",
  2097  					"ports.20.b.#":   "1",
  2098  					"ports.20.b.0":   "100",
  2099  				},
  2100  			},
  2101  		},
  2102  
  2103  		/*
  2104  		 * PARTIAL STATES
  2105  		 */
  2106  
  2107  		// #12 Basic primitive
  2108  		{
  2109  			Schema: map[string]*Schema{
  2110  				"availability_zone": &Schema{
  2111  					Type:     TypeString,
  2112  					Optional: true,
  2113  					Computed: true,
  2114  					ForceNew: true,
  2115  				},
  2116  			},
  2117  
  2118  			State: nil,
  2119  
  2120  			Diff: &terraform.InstanceDiff{
  2121  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2122  					"availability_zone": &terraform.ResourceAttrDiff{
  2123  						Old:         "",
  2124  						New:         "foo",
  2125  						RequiresNew: true,
  2126  					},
  2127  				},
  2128  			},
  2129  
  2130  			Partial: []string{},
  2131  
  2132  			Result: &terraform.InstanceState{
  2133  				Attributes: map[string]string{},
  2134  			},
  2135  		},
  2136  
  2137  		// #13 List
  2138  		{
  2139  			Schema: map[string]*Schema{
  2140  				"ports": &Schema{
  2141  					Type:     TypeList,
  2142  					Required: true,
  2143  					Elem:     &Schema{Type: TypeInt},
  2144  				},
  2145  			},
  2146  
  2147  			State: &terraform.InstanceState{
  2148  				Attributes: map[string]string{
  2149  					"ports.#": "1",
  2150  					"ports.0": "80",
  2151  				},
  2152  			},
  2153  
  2154  			Diff: &terraform.InstanceDiff{
  2155  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2156  					"ports.#": &terraform.ResourceAttrDiff{
  2157  						Old: "1",
  2158  						New: "2",
  2159  					},
  2160  					"ports.1": &terraform.ResourceAttrDiff{
  2161  						Old: "",
  2162  						New: "100",
  2163  					},
  2164  				},
  2165  			},
  2166  
  2167  			Partial: []string{},
  2168  
  2169  			Result: &terraform.InstanceState{
  2170  				Attributes: map[string]string{
  2171  					"ports.#": "1",
  2172  					"ports.0": "80",
  2173  				},
  2174  			},
  2175  		},
  2176  
  2177  		// #14
  2178  		{
  2179  			Schema: map[string]*Schema{
  2180  				"ports": &Schema{
  2181  					Type:     TypeList,
  2182  					Optional: true,
  2183  					Computed: true,
  2184  					Elem:     &Schema{Type: TypeInt},
  2185  				},
  2186  			},
  2187  
  2188  			State: nil,
  2189  
  2190  			Diff: &terraform.InstanceDiff{
  2191  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2192  					"ports.#": &terraform.ResourceAttrDiff{
  2193  						Old:         "",
  2194  						NewComputed: true,
  2195  					},
  2196  				},
  2197  			},
  2198  
  2199  			Partial: []string{},
  2200  
  2201  			Set: map[string]interface{}{
  2202  				"ports": []interface{}{},
  2203  			},
  2204  
  2205  			Result: &terraform.InstanceState{
  2206  				Attributes: map[string]string{},
  2207  			},
  2208  		},
  2209  
  2210  		// #15 List of resources
  2211  		{
  2212  			Schema: map[string]*Schema{
  2213  				"ingress": &Schema{
  2214  					Type:     TypeList,
  2215  					Required: true,
  2216  					Elem: &Resource{
  2217  						Schema: map[string]*Schema{
  2218  							"from": &Schema{
  2219  								Type:     TypeInt,
  2220  								Required: true,
  2221  							},
  2222  						},
  2223  					},
  2224  				},
  2225  			},
  2226  
  2227  			State: &terraform.InstanceState{
  2228  				Attributes: map[string]string{
  2229  					"ingress.#":      "1",
  2230  					"ingress.0.from": "80",
  2231  				},
  2232  			},
  2233  
  2234  			Diff: &terraform.InstanceDiff{
  2235  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2236  					"ingress.#": &terraform.ResourceAttrDiff{
  2237  						Old: "1",
  2238  						New: "2",
  2239  					},
  2240  					"ingress.0.from": &terraform.ResourceAttrDiff{
  2241  						Old: "80",
  2242  						New: "150",
  2243  					},
  2244  					"ingress.1.from": &terraform.ResourceAttrDiff{
  2245  						Old: "",
  2246  						New: "100",
  2247  					},
  2248  				},
  2249  			},
  2250  
  2251  			Partial: []string{},
  2252  
  2253  			Result: &terraform.InstanceState{
  2254  				Attributes: map[string]string{
  2255  					"ingress.#":      "1",
  2256  					"ingress.0.from": "80",
  2257  				},
  2258  			},
  2259  		},
  2260  
  2261  		// #16 List of maps
  2262  		{
  2263  			Schema: map[string]*Schema{
  2264  				"config_vars": &Schema{
  2265  					Type:     TypeList,
  2266  					Optional: true,
  2267  					Computed: true,
  2268  					Elem: &Schema{
  2269  						Type: TypeMap,
  2270  					},
  2271  				},
  2272  			},
  2273  
  2274  			State: &terraform.InstanceState{
  2275  				Attributes: map[string]string{
  2276  					"config_vars.#":     "2",
  2277  					"config_vars.0.foo": "bar",
  2278  					"config_vars.0.bar": "bar",
  2279  					"config_vars.1.bar": "baz",
  2280  				},
  2281  			},
  2282  
  2283  			Diff: &terraform.InstanceDiff{
  2284  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2285  					"config_vars.0.bar": &terraform.ResourceAttrDiff{
  2286  						NewRemoved: true,
  2287  					},
  2288  				},
  2289  			},
  2290  
  2291  			Set: map[string]interface{}{
  2292  				"config_vars": []map[string]interface{}{
  2293  					map[string]interface{}{
  2294  						"foo": "bar",
  2295  					},
  2296  					map[string]interface{}{
  2297  						"baz": "bang",
  2298  					},
  2299  				},
  2300  			},
  2301  
  2302  			Partial: []string{},
  2303  
  2304  			Result: &terraform.InstanceState{
  2305  				Attributes: map[string]string{
  2306  					// TODO: broken, shouldn't bar be removed?
  2307  					"config_vars.#":     "2",
  2308  					"config_vars.0.#":   "2",
  2309  					"config_vars.0.foo": "bar",
  2310  					"config_vars.0.bar": "bar",
  2311  					"config_vars.1.#":   "1",
  2312  					"config_vars.1.bar": "baz",
  2313  				},
  2314  			},
  2315  		},
  2316  
  2317  		// #17 Sets
  2318  		{
  2319  			Schema: map[string]*Schema{
  2320  				"ports": &Schema{
  2321  					Type:     TypeSet,
  2322  					Optional: true,
  2323  					Computed: true,
  2324  					Elem:     &Schema{Type: TypeInt},
  2325  					Set: func(a interface{}) int {
  2326  						return a.(int)
  2327  					},
  2328  				},
  2329  			},
  2330  
  2331  			State: &terraform.InstanceState{
  2332  				Attributes: map[string]string{
  2333  					"ports.#":   "3",
  2334  					"ports.100": "100",
  2335  					"ports.80":  "80",
  2336  					"ports.81":  "81",
  2337  				},
  2338  			},
  2339  
  2340  			Diff: &terraform.InstanceDiff{
  2341  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2342  					"ports.120": &terraform.ResourceAttrDiff{
  2343  						New: "120",
  2344  					},
  2345  				},
  2346  			},
  2347  
  2348  			Partial: []string{},
  2349  
  2350  			Result: &terraform.InstanceState{
  2351  				Attributes: map[string]string{
  2352  					"ports.#":   "3",
  2353  					"ports.80":  "80",
  2354  					"ports.81":  "81",
  2355  					"ports.100": "100",
  2356  				},
  2357  			},
  2358  		},
  2359  
  2360  		// #18
  2361  		{
  2362  			Schema: map[string]*Schema{
  2363  				"ports": &Schema{
  2364  					Type:     TypeSet,
  2365  					Optional: true,
  2366  					Computed: true,
  2367  					Elem:     &Schema{Type: TypeInt},
  2368  					Set: func(a interface{}) int {
  2369  						return a.(int)
  2370  					},
  2371  				},
  2372  			},
  2373  
  2374  			State: nil,
  2375  
  2376  			Diff: &terraform.InstanceDiff{
  2377  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2378  					"ports.#": &terraform.ResourceAttrDiff{
  2379  						Old:         "",
  2380  						NewComputed: true,
  2381  					},
  2382  				},
  2383  			},
  2384  
  2385  			Partial: []string{},
  2386  
  2387  			Result: &terraform.InstanceState{
  2388  				Attributes: map[string]string{},
  2389  			},
  2390  		},
  2391  
  2392  		// #19 Maps
  2393  		{
  2394  			Schema: map[string]*Schema{
  2395  				"tags": &Schema{
  2396  					Type:     TypeMap,
  2397  					Optional: true,
  2398  					Computed: true,
  2399  				},
  2400  			},
  2401  
  2402  			State: nil,
  2403  
  2404  			Diff: &terraform.InstanceDiff{
  2405  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2406  					"tags.Name": &terraform.ResourceAttrDiff{
  2407  						Old: "",
  2408  						New: "foo",
  2409  					},
  2410  				},
  2411  			},
  2412  
  2413  			Result: &terraform.InstanceState{
  2414  				Attributes: map[string]string{
  2415  					"tags.#":    "1",
  2416  					"tags.Name": "foo",
  2417  				},
  2418  			},
  2419  		},
  2420  
  2421  		// #20
  2422  		{
  2423  			Schema: map[string]*Schema{
  2424  				"tags": &Schema{
  2425  					Type:     TypeMap,
  2426  					Optional: true,
  2427  					Computed: true,
  2428  				},
  2429  			},
  2430  
  2431  			State: nil,
  2432  
  2433  			Diff: &terraform.InstanceDiff{
  2434  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2435  					"tags.Name": &terraform.ResourceAttrDiff{
  2436  						Old: "",
  2437  						New: "foo",
  2438  					},
  2439  				},
  2440  			},
  2441  
  2442  			Set: map[string]interface{}{
  2443  				"tags": map[string]string{},
  2444  			},
  2445  
  2446  			Result: &terraform.InstanceState{
  2447  				Attributes: map[string]string{},
  2448  			},
  2449  		},
  2450  
  2451  		// #21
  2452  		{
  2453  			Schema: map[string]*Schema{
  2454  				"foo": &Schema{
  2455  					Type:     TypeString,
  2456  					Optional: true,
  2457  					Computed: true,
  2458  				},
  2459  			},
  2460  
  2461  			State: nil,
  2462  
  2463  			Diff: &terraform.InstanceDiff{
  2464  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2465  					"foo": &terraform.ResourceAttrDiff{
  2466  						NewComputed: true,
  2467  					},
  2468  				},
  2469  			},
  2470  
  2471  			Result: &terraform.InstanceState{
  2472  				Attributes: map[string]string{},
  2473  			},
  2474  		},
  2475  
  2476  		// #22
  2477  		{
  2478  			Schema: map[string]*Schema{
  2479  				"foo": &Schema{
  2480  					Type:     TypeString,
  2481  					Optional: true,
  2482  					Computed: true,
  2483  				},
  2484  			},
  2485  
  2486  			State: nil,
  2487  
  2488  			Diff: &terraform.InstanceDiff{
  2489  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2490  					"foo": &terraform.ResourceAttrDiff{
  2491  						NewComputed: true,
  2492  					},
  2493  				},
  2494  			},
  2495  
  2496  			Set: map[string]interface{}{
  2497  				"foo": "bar",
  2498  			},
  2499  
  2500  			Result: &terraform.InstanceState{
  2501  				Attributes: map[string]string{
  2502  					"foo": "bar",
  2503  				},
  2504  			},
  2505  		},
  2506  
  2507  		// #23 Set of maps
  2508  		{
  2509  			Schema: map[string]*Schema{
  2510  				"ports": &Schema{
  2511  					Type:     TypeSet,
  2512  					Optional: true,
  2513  					Computed: true,
  2514  					Elem: &Resource{
  2515  						Schema: map[string]*Schema{
  2516  							"index": &Schema{Type: TypeInt},
  2517  							"uuids": &Schema{Type: TypeMap},
  2518  						},
  2519  					},
  2520  					Set: func(a interface{}) int {
  2521  						m := a.(map[string]interface{})
  2522  						return m["index"].(int)
  2523  					},
  2524  				},
  2525  			},
  2526  
  2527  			State: nil,
  2528  
  2529  			Diff: &terraform.InstanceDiff{
  2530  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2531  					"ports.10.uuids.#": &terraform.ResourceAttrDiff{
  2532  						NewComputed: true,
  2533  					},
  2534  				},
  2535  			},
  2536  
  2537  			Set: map[string]interface{}{
  2538  				"ports": []interface{}{
  2539  					map[string]interface{}{
  2540  						"index": 10,
  2541  						"uuids": map[string]interface{}{
  2542  							"80": "value",
  2543  						},
  2544  					},
  2545  				},
  2546  			},
  2547  
  2548  			Result: &terraform.InstanceState{
  2549  				Attributes: map[string]string{
  2550  					"ports.#":           "1",
  2551  					"ports.10.index":    "10",
  2552  					"ports.10.uuids.#":  "1",
  2553  					"ports.10.uuids.80": "value",
  2554  				},
  2555  			},
  2556  		},
  2557  
  2558  		// #24
  2559  		{
  2560  			Schema: map[string]*Schema{
  2561  				"ports": &Schema{
  2562  					Type:     TypeSet,
  2563  					Optional: true,
  2564  					Computed: true,
  2565  					Elem:     &Schema{Type: TypeInt},
  2566  					Set: func(a interface{}) int {
  2567  						return a.(int)
  2568  					},
  2569  				},
  2570  			},
  2571  
  2572  			State: &terraform.InstanceState{
  2573  				Attributes: map[string]string{
  2574  					"ports.#":   "3",
  2575  					"ports.100": "100",
  2576  					"ports.80":  "80",
  2577  					"ports.81":  "81",
  2578  				},
  2579  			},
  2580  
  2581  			Diff: &terraform.InstanceDiff{
  2582  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2583  					"ports.#": &terraform.ResourceAttrDiff{
  2584  						Old: "3",
  2585  						New: "0",
  2586  					},
  2587  				},
  2588  			},
  2589  
  2590  			Result: &terraform.InstanceState{
  2591  				Attributes: map[string]string{
  2592  					"ports.#": "0",
  2593  				},
  2594  			},
  2595  		},
  2596  
  2597  		// #25
  2598  		{
  2599  			Schema: map[string]*Schema{
  2600  				"ports": &Schema{
  2601  					Type:     TypeSet,
  2602  					Optional: true,
  2603  					Computed: true,
  2604  					Elem:     &Schema{Type: TypeInt},
  2605  					Set: func(a interface{}) int {
  2606  						return a.(int)
  2607  					},
  2608  				},
  2609  			},
  2610  
  2611  			State: nil,
  2612  
  2613  			Diff: nil,
  2614  
  2615  			Set: map[string]interface{}{
  2616  				"ports": []interface{}{},
  2617  			},
  2618  
  2619  			Result: &terraform.InstanceState{
  2620  				Attributes: map[string]string{
  2621  					"ports.#": "0",
  2622  				},
  2623  			},
  2624  		},
  2625  
  2626  		// #26
  2627  		{
  2628  			Schema: map[string]*Schema{
  2629  				"ports": &Schema{
  2630  					Type:     TypeList,
  2631  					Optional: true,
  2632  					Computed: true,
  2633  					Elem:     &Schema{Type: TypeInt},
  2634  				},
  2635  			},
  2636  
  2637  			State: nil,
  2638  
  2639  			Diff: nil,
  2640  
  2641  			Set: map[string]interface{}{
  2642  				"ports": []interface{}{},
  2643  			},
  2644  
  2645  			Result: &terraform.InstanceState{
  2646  				Attributes: map[string]string{
  2647  					"ports.#": "0",
  2648  				},
  2649  			},
  2650  		},
  2651  
  2652  		// #27 Set lists
  2653  		{
  2654  			Schema: map[string]*Schema{
  2655  				"ports": &Schema{
  2656  					Type:     TypeList,
  2657  					Optional: true,
  2658  					Computed: true,
  2659  					Elem: &Resource{
  2660  						Schema: map[string]*Schema{
  2661  							"index": &Schema{Type: TypeInt},
  2662  							"uuids": &Schema{Type: TypeMap},
  2663  						},
  2664  					},
  2665  				},
  2666  			},
  2667  
  2668  			State: nil,
  2669  
  2670  			Diff: &terraform.InstanceDiff{
  2671  				Attributes: map[string]*terraform.ResourceAttrDiff{
  2672  					"ports.#": &terraform.ResourceAttrDiff{
  2673  						NewComputed: true,
  2674  					},
  2675  				},
  2676  			},
  2677  
  2678  			Set: map[string]interface{}{
  2679  				"ports": []interface{}{
  2680  					map[string]interface{}{
  2681  						"index": 10,
  2682  						"uuids": map[string]interface{}{
  2683  							"80": "value",
  2684  						},
  2685  					},
  2686  				},
  2687  			},
  2688  
  2689  			Result: &terraform.InstanceState{
  2690  				Attributes: map[string]string{
  2691  					"ports.#":          "1",
  2692  					"ports.0.index":    "10",
  2693  					"ports.0.uuids.#":  "1",
  2694  					"ports.0.uuids.80": "value",
  2695  				},
  2696  			},
  2697  		},
  2698  	}
  2699  
  2700  	for i, tc := range cases {
  2701  		d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
  2702  		if err != nil {
  2703  			t.Fatalf("err: %s", err)
  2704  		}
  2705  
  2706  		for k, v := range tc.Set {
  2707  			if err := d.Set(k, v); err != nil {
  2708  				t.Fatalf("%d err: %s", i, err)
  2709  			}
  2710  		}
  2711  
  2712  		// Set an ID so that the state returned is not nil
  2713  		idSet := false
  2714  		if d.Id() == "" {
  2715  			idSet = true
  2716  			d.SetId("foo")
  2717  		}
  2718  
  2719  		// If we have partial, then enable partial state mode.
  2720  		if tc.Partial != nil {
  2721  			d.Partial(true)
  2722  			for _, k := range tc.Partial {
  2723  				d.SetPartial(k)
  2724  			}
  2725  		}
  2726  
  2727  		actual := d.State()
  2728  
  2729  		// If we set an ID, then undo what we did so the comparison works
  2730  		if actual != nil && idSet {
  2731  			actual.ID = ""
  2732  			delete(actual.Attributes, "id")
  2733  		}
  2734  
  2735  		if !reflect.DeepEqual(actual, tc.Result) {
  2736  			t.Fatalf("Bad: %d\n\n%#v\n\nExpected:\n\n%#v", i, actual, tc.Result)
  2737  		}
  2738  	}
  2739  }
  2740  
  2741  func TestResourceDataSetConnInfo(t *testing.T) {
  2742  	d := &ResourceData{}
  2743  	d.SetId("foo")
  2744  	d.SetConnInfo(map[string]string{
  2745  		"foo": "bar",
  2746  	})
  2747  
  2748  	expected := map[string]string{
  2749  		"foo": "bar",
  2750  	}
  2751  
  2752  	actual := d.State()
  2753  	if !reflect.DeepEqual(actual.Ephemeral.ConnInfo, expected) {
  2754  		t.Fatalf("bad: %#v", actual)
  2755  	}
  2756  }
  2757  
  2758  func TestResourceDataSetId(t *testing.T) {
  2759  	d := &ResourceData{}
  2760  	d.SetId("foo")
  2761  
  2762  	actual := d.State()
  2763  	if actual.ID != "foo" {
  2764  		t.Fatalf("bad: %#v", actual)
  2765  	}
  2766  }
  2767  
  2768  func TestResourceDataSetId_clear(t *testing.T) {
  2769  	d := &ResourceData{
  2770  		state: &terraform.InstanceState{ID: "bar"},
  2771  	}
  2772  	d.SetId("")
  2773  
  2774  	actual := d.State()
  2775  	if actual != nil {
  2776  		t.Fatalf("bad: %#v", actual)
  2777  	}
  2778  }
  2779  
  2780  func TestResourceDataSetId_override(t *testing.T) {
  2781  	d := &ResourceData{
  2782  		state: &terraform.InstanceState{ID: "bar"},
  2783  	}
  2784  	d.SetId("foo")
  2785  
  2786  	actual := d.State()
  2787  	if actual.ID != "foo" {
  2788  		t.Fatalf("bad: %#v", actual)
  2789  	}
  2790  }