github.com/hs0210/hashicorp-terraform@v0.11.12-beta1/helper/schema/field_writer_map_test.go (about)

     1  package schema
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  )
     7  
     8  func TestMapFieldWriter_impl(t *testing.T) {
     9  	var _ FieldWriter = new(MapFieldWriter)
    10  }
    11  
    12  func TestMapFieldWriter(t *testing.T) {
    13  	schema := map[string]*Schema{
    14  		"bool":   &Schema{Type: TypeBool},
    15  		"int":    &Schema{Type: TypeInt},
    16  		"string": &Schema{Type: TypeString},
    17  		"list": &Schema{
    18  			Type: TypeList,
    19  			Elem: &Schema{Type: TypeString},
    20  		},
    21  		"listInt": &Schema{
    22  			Type: TypeList,
    23  			Elem: &Schema{Type: TypeInt},
    24  		},
    25  		"listResource": &Schema{
    26  			Type:     TypeList,
    27  			Optional: true,
    28  			Computed: true,
    29  			Elem: &Resource{
    30  				Schema: map[string]*Schema{
    31  					"value": &Schema{
    32  						Type:     TypeInt,
    33  						Optional: true,
    34  					},
    35  				},
    36  			},
    37  		},
    38  		"map": &Schema{Type: TypeMap},
    39  		"set": &Schema{
    40  			Type: TypeSet,
    41  			Elem: &Schema{Type: TypeInt},
    42  			Set: func(a interface{}) int {
    43  				return a.(int)
    44  			},
    45  		},
    46  		"setDeep": &Schema{
    47  			Type: TypeSet,
    48  			Elem: &Resource{
    49  				Schema: map[string]*Schema{
    50  					"index": &Schema{Type: TypeInt},
    51  					"value": &Schema{Type: TypeString},
    52  				},
    53  			},
    54  			Set: func(a interface{}) int {
    55  				return a.(map[string]interface{})["index"].(int)
    56  			},
    57  		},
    58  	}
    59  
    60  	cases := map[string]struct {
    61  		Addr  []string
    62  		Value interface{}
    63  		Err   bool
    64  		Out   map[string]string
    65  	}{
    66  		"noexist": {
    67  			[]string{"noexist"},
    68  			42,
    69  			true,
    70  			map[string]string{},
    71  		},
    72  
    73  		"bool": {
    74  			[]string{"bool"},
    75  			false,
    76  			false,
    77  			map[string]string{
    78  				"bool": "false",
    79  			},
    80  		},
    81  
    82  		"int": {
    83  			[]string{"int"},
    84  			42,
    85  			false,
    86  			map[string]string{
    87  				"int": "42",
    88  			},
    89  		},
    90  
    91  		"string": {
    92  			[]string{"string"},
    93  			"42",
    94  			false,
    95  			map[string]string{
    96  				"string": "42",
    97  			},
    98  		},
    99  
   100  		"string nil": {
   101  			[]string{"string"},
   102  			nil,
   103  			false,
   104  			map[string]string{
   105  				"string": "",
   106  			},
   107  		},
   108  
   109  		"list of resources": {
   110  			[]string{"listResource"},
   111  			[]interface{}{
   112  				map[string]interface{}{
   113  					"value": 80,
   114  				},
   115  			},
   116  			false,
   117  			map[string]string{
   118  				"listResource.#":       "1",
   119  				"listResource.0.value": "80",
   120  			},
   121  		},
   122  
   123  		"list of resources empty": {
   124  			[]string{"listResource"},
   125  			[]interface{}{},
   126  			false,
   127  			map[string]string{
   128  				"listResource.#": "0",
   129  			},
   130  		},
   131  
   132  		"list of resources nil": {
   133  			[]string{"listResource"},
   134  			nil,
   135  			false,
   136  			map[string]string{
   137  				"listResource.#": "0",
   138  			},
   139  		},
   140  
   141  		"list of strings": {
   142  			[]string{"list"},
   143  			[]interface{}{"foo", "bar"},
   144  			false,
   145  			map[string]string{
   146  				"list.#": "2",
   147  				"list.0": "foo",
   148  				"list.1": "bar",
   149  			},
   150  		},
   151  
   152  		"list element": {
   153  			[]string{"list", "0"},
   154  			"string",
   155  			true,
   156  			map[string]string{},
   157  		},
   158  
   159  		"map": {
   160  			[]string{"map"},
   161  			map[string]interface{}{"foo": "bar"},
   162  			false,
   163  			map[string]string{
   164  				"map.%":   "1",
   165  				"map.foo": "bar",
   166  			},
   167  		},
   168  
   169  		"map delete": {
   170  			[]string{"map"},
   171  			nil,
   172  			false,
   173  			map[string]string{
   174  				"map": "",
   175  			},
   176  		},
   177  
   178  		"map element": {
   179  			[]string{"map", "foo"},
   180  			"bar",
   181  			true,
   182  			map[string]string{},
   183  		},
   184  
   185  		"set": {
   186  			[]string{"set"},
   187  			[]interface{}{1, 2, 5},
   188  			false,
   189  			map[string]string{
   190  				"set.#": "3",
   191  				"set.1": "1",
   192  				"set.2": "2",
   193  				"set.5": "5",
   194  			},
   195  		},
   196  
   197  		"set nil": {
   198  			[]string{"set"},
   199  			nil,
   200  			false,
   201  			map[string]string{
   202  				"set.#": "0",
   203  			},
   204  		},
   205  
   206  		"set resource": {
   207  			[]string{"setDeep"},
   208  			[]interface{}{
   209  				map[string]interface{}{
   210  					"index": 10,
   211  					"value": "foo",
   212  				},
   213  				map[string]interface{}{
   214  					"index": 50,
   215  					"value": "bar",
   216  				},
   217  			},
   218  			false,
   219  			map[string]string{
   220  				"setDeep.#":        "2",
   221  				"setDeep.10.index": "10",
   222  				"setDeep.10.value": "foo",
   223  				"setDeep.50.index": "50",
   224  				"setDeep.50.value": "bar",
   225  			},
   226  		},
   227  
   228  		"set element": {
   229  			[]string{"set", "5"},
   230  			5,
   231  			true,
   232  			map[string]string{},
   233  		},
   234  
   235  		"full object": {
   236  			nil,
   237  			map[string]interface{}{
   238  				"string": "foo",
   239  				"list":   []interface{}{"foo", "bar"},
   240  			},
   241  			false,
   242  			map[string]string{
   243  				"string": "foo",
   244  				"list.#": "2",
   245  				"list.0": "foo",
   246  				"list.1": "bar",
   247  			},
   248  		},
   249  	}
   250  
   251  	for name, tc := range cases {
   252  		w := &MapFieldWriter{Schema: schema}
   253  		err := w.WriteField(tc.Addr, tc.Value)
   254  		if err != nil != tc.Err {
   255  			t.Fatalf("%s: err: %s", name, err)
   256  		}
   257  
   258  		actual := w.Map()
   259  		if !reflect.DeepEqual(actual, tc.Out) {
   260  			t.Fatalf("%s: bad: %#v", name, actual)
   261  		}
   262  	}
   263  }
   264  
   265  func TestMapFieldWriterCleanSet(t *testing.T) {
   266  	schema := map[string]*Schema{
   267  		"setDeep": &Schema{
   268  			Type: TypeSet,
   269  			Elem: &Resource{
   270  				Schema: map[string]*Schema{
   271  					"index": &Schema{Type: TypeInt},
   272  					"value": &Schema{Type: TypeString},
   273  				},
   274  			},
   275  			Set: func(a interface{}) int {
   276  				return a.(map[string]interface{})["index"].(int)
   277  			},
   278  		},
   279  	}
   280  
   281  	values := []struct {
   282  		Addr  []string
   283  		Value interface{}
   284  		Out   map[string]string
   285  	}{
   286  		{
   287  			[]string{"setDeep"},
   288  			[]interface{}{
   289  				map[string]interface{}{
   290  					"index": 10,
   291  					"value": "foo",
   292  				},
   293  				map[string]interface{}{
   294  					"index": 50,
   295  					"value": "bar",
   296  				},
   297  			},
   298  			map[string]string{
   299  				"setDeep.#":        "2",
   300  				"setDeep.10.index": "10",
   301  				"setDeep.10.value": "foo",
   302  				"setDeep.50.index": "50",
   303  				"setDeep.50.value": "bar",
   304  			},
   305  		},
   306  		{
   307  			[]string{"setDeep"},
   308  			[]interface{}{
   309  				map[string]interface{}{
   310  					"index": 20,
   311  					"value": "baz",
   312  				},
   313  				map[string]interface{}{
   314  					"index": 60,
   315  					"value": "qux",
   316  				},
   317  			},
   318  			map[string]string{
   319  				"setDeep.#":        "2",
   320  				"setDeep.20.index": "20",
   321  				"setDeep.20.value": "baz",
   322  				"setDeep.60.index": "60",
   323  				"setDeep.60.value": "qux",
   324  			},
   325  		},
   326  		{
   327  			[]string{"setDeep"},
   328  			[]interface{}{
   329  				map[string]interface{}{
   330  					"index": 30,
   331  					"value": "one",
   332  				},
   333  				map[string]interface{}{
   334  					"index": 70,
   335  					"value": "two",
   336  				},
   337  			},
   338  			map[string]string{
   339  				"setDeep.#":        "2",
   340  				"setDeep.30.index": "30",
   341  				"setDeep.30.value": "one",
   342  				"setDeep.70.index": "70",
   343  				"setDeep.70.value": "two",
   344  			},
   345  		},
   346  	}
   347  
   348  	w := &MapFieldWriter{Schema: schema}
   349  
   350  	for n, tc := range values {
   351  		err := w.WriteField(tc.Addr, tc.Value)
   352  		if err != nil {
   353  			t.Fatalf("%d: err: %s", n, err)
   354  		}
   355  
   356  		actual := w.Map()
   357  		if !reflect.DeepEqual(actual, tc.Out) {
   358  			t.Fatalf("%d: bad: %#v", n, actual)
   359  		}
   360  	}
   361  }
   362  
   363  func TestMapFieldWriterCleanList(t *testing.T) {
   364  	schema := map[string]*Schema{
   365  		"listDeep": &Schema{
   366  			Type: TypeList,
   367  			Elem: &Resource{
   368  				Schema: map[string]*Schema{
   369  					"thing1": &Schema{Type: TypeString},
   370  					"thing2": &Schema{Type: TypeString},
   371  				},
   372  			},
   373  		},
   374  	}
   375  
   376  	values := []struct {
   377  		Addr  []string
   378  		Value interface{}
   379  		Out   map[string]string
   380  	}{
   381  		{
   382  			// Base list
   383  			[]string{"listDeep"},
   384  			[]interface{}{
   385  				map[string]interface{}{
   386  					"thing1": "a",
   387  					"thing2": "b",
   388  				},
   389  				map[string]interface{}{
   390  					"thing1": "c",
   391  					"thing2": "d",
   392  				},
   393  				map[string]interface{}{
   394  					"thing1": "e",
   395  					"thing2": "f",
   396  				},
   397  				map[string]interface{}{
   398  					"thing1": "g",
   399  					"thing2": "h",
   400  				},
   401  			},
   402  			map[string]string{
   403  				"listDeep.#":        "4",
   404  				"listDeep.0.thing1": "a",
   405  				"listDeep.0.thing2": "b",
   406  				"listDeep.1.thing1": "c",
   407  				"listDeep.1.thing2": "d",
   408  				"listDeep.2.thing1": "e",
   409  				"listDeep.2.thing2": "f",
   410  				"listDeep.3.thing1": "g",
   411  				"listDeep.3.thing2": "h",
   412  			},
   413  		},
   414  		{
   415  			// Remove an element
   416  			[]string{"listDeep"},
   417  			[]interface{}{
   418  				map[string]interface{}{
   419  					"thing1": "a",
   420  					"thing2": "b",
   421  				},
   422  				map[string]interface{}{
   423  					"thing1": "c",
   424  					"thing2": "d",
   425  				},
   426  				map[string]interface{}{
   427  					"thing1": "e",
   428  					"thing2": "f",
   429  				},
   430  			},
   431  			map[string]string{
   432  				"listDeep.#":        "3",
   433  				"listDeep.0.thing1": "a",
   434  				"listDeep.0.thing2": "b",
   435  				"listDeep.1.thing1": "c",
   436  				"listDeep.1.thing2": "d",
   437  				"listDeep.2.thing1": "e",
   438  				"listDeep.2.thing2": "f",
   439  			},
   440  		},
   441  		{
   442  			// Rewrite with missing keys. This should normally not be necessary, as
   443  			// hopefully the writers are writing zero values as necessary, but for
   444  			// brevity we want to make sure that what exists in the writer is exactly
   445  			// what the last write looked like coming from the provider.
   446  			[]string{"listDeep"},
   447  			[]interface{}{
   448  				map[string]interface{}{
   449  					"thing1": "a",
   450  				},
   451  				map[string]interface{}{
   452  					"thing1": "c",
   453  				},
   454  				map[string]interface{}{
   455  					"thing1": "e",
   456  				},
   457  			},
   458  			map[string]string{
   459  				"listDeep.#":        "3",
   460  				"listDeep.0.thing1": "a",
   461  				"listDeep.1.thing1": "c",
   462  				"listDeep.2.thing1": "e",
   463  			},
   464  		},
   465  	}
   466  
   467  	w := &MapFieldWriter{Schema: schema}
   468  
   469  	for n, tc := range values {
   470  		err := w.WriteField(tc.Addr, tc.Value)
   471  		if err != nil {
   472  			t.Fatalf("%d: err: %s", n, err)
   473  		}
   474  
   475  		actual := w.Map()
   476  		if !reflect.DeepEqual(actual, tc.Out) {
   477  			t.Fatalf("%d: bad: %#v", n, actual)
   478  		}
   479  	}
   480  }
   481  
   482  func TestMapFieldWriterCleanMap(t *testing.T) {
   483  	schema := map[string]*Schema{
   484  		"map": &Schema{
   485  			Type: TypeMap,
   486  		},
   487  	}
   488  
   489  	values := []struct {
   490  		Value interface{}
   491  		Out   map[string]string
   492  	}{
   493  		{
   494  			// Base map
   495  			map[string]interface{}{
   496  				"thing1": "a",
   497  				"thing2": "b",
   498  				"thing3": "c",
   499  				"thing4": "d",
   500  			},
   501  			map[string]string{
   502  				"map.%":      "4",
   503  				"map.thing1": "a",
   504  				"map.thing2": "b",
   505  				"map.thing3": "c",
   506  				"map.thing4": "d",
   507  			},
   508  		},
   509  		{
   510  			// Base map
   511  			map[string]interface{}{
   512  				"thing1": "a",
   513  				"thing2": "b",
   514  				"thing4": "d",
   515  			},
   516  			map[string]string{
   517  				"map.%":      "3",
   518  				"map.thing1": "a",
   519  				"map.thing2": "b",
   520  				"map.thing4": "d",
   521  			},
   522  		},
   523  	}
   524  
   525  	w := &MapFieldWriter{Schema: schema}
   526  
   527  	for n, tc := range values {
   528  		err := w.WriteField([]string{"map"}, tc.Value)
   529  		if err != nil {
   530  			t.Fatalf("%d: err: %s", n, err)
   531  		}
   532  
   533  		actual := w.Map()
   534  		if !reflect.DeepEqual(actual, tc.Out) {
   535  			t.Fatalf("%d: bad: %#v", n, actual)
   536  		}
   537  	}
   538  }