github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/blueprint/unpack_test.go (about)

     1  // Copyright 2014 Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package blueprint
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"reflect"
    21  	"testing"
    22  	"text/scanner"
    23  
    24  	"github.com/google/blueprint/parser"
    25  	"github.com/google/blueprint/proptools"
    26  )
    27  
    28  var validUnpackTestCases = []struct {
    29  	input  string
    30  	output []interface{}
    31  	empty  []interface{}
    32  	errs   []error
    33  }{
    34  	{
    35  		input: `
    36  			m {
    37  				name: "abc",
    38  				blank: "",
    39  			}
    40  		`,
    41  		output: []interface{}{
    42  			struct {
    43  				Name  *string
    44  				Blank *string
    45  				Unset *string
    46  			}{
    47  				Name:  proptools.StringPtr("abc"),
    48  				Blank: proptools.StringPtr(""),
    49  				Unset: nil,
    50  			},
    51  		},
    52  	},
    53  
    54  	{
    55  		input: `
    56  			m {
    57  				name: "abc",
    58  			}
    59  		`,
    60  		output: []interface{}{
    61  			struct {
    62  				Name string
    63  			}{
    64  				Name: "abc",
    65  			},
    66  		},
    67  	},
    68  
    69  	{
    70  		input: `
    71  			m {
    72  				isGood: true,
    73  			}
    74  		`,
    75  		output: []interface{}{
    76  			struct {
    77  				IsGood bool
    78  			}{
    79  				IsGood: true,
    80  			},
    81  		},
    82  	},
    83  
    84  	{
    85  		input: `
    86  			m {
    87  				isGood: true,
    88  				isBad: false,
    89  			}
    90  		`,
    91  		output: []interface{}{
    92  			struct {
    93  				IsGood *bool
    94  				IsBad  *bool
    95  				IsUgly *bool
    96  			}{
    97  				IsGood: proptools.BoolPtr(true),
    98  				IsBad:  proptools.BoolPtr(false),
    99  				IsUgly: nil,
   100  			},
   101  		},
   102  	},
   103  
   104  	{
   105  		input: `
   106  			m {
   107  				stuff: ["asdf", "jkl;", "qwert",
   108  					"uiop", "bnm,"],
   109  				empty: []
   110  			}
   111  		`,
   112  		output: []interface{}{
   113  			struct {
   114  				Stuff []string
   115  				Empty []string
   116  				Nil   []string
   117  			}{
   118  				Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
   119  				Empty: []string{},
   120  				Nil:   nil,
   121  			},
   122  		},
   123  	},
   124  
   125  	{
   126  		input: `
   127  			m {
   128  				nested: {
   129  					name: "abc",
   130  				}
   131  			}
   132  		`,
   133  		output: []interface{}{
   134  			struct {
   135  				Nested struct {
   136  					Name string
   137  				}
   138  			}{
   139  				Nested: struct{ Name string }{
   140  					Name: "abc",
   141  				},
   142  			},
   143  		},
   144  	},
   145  
   146  	{
   147  		input: `
   148  			m {
   149  				nested: {
   150  					name: "def",
   151  				}
   152  			}
   153  		`,
   154  		output: []interface{}{
   155  			struct {
   156  				Nested interface{}
   157  			}{
   158  				Nested: &struct{ Name string }{
   159  					Name: "def",
   160  				},
   161  			},
   162  		},
   163  	},
   164  
   165  	{
   166  		input: `
   167  			m {
   168  				nested: {
   169  					foo: "abc",
   170  				},
   171  				bar: false,
   172  				baz: ["def", "ghi"],
   173  			}
   174  		`,
   175  		output: []interface{}{
   176  			struct {
   177  				Nested struct {
   178  					Foo string
   179  				}
   180  				Bar bool
   181  				Baz []string
   182  			}{
   183  				Nested: struct{ Foo string }{
   184  					Foo: "abc",
   185  				},
   186  				Bar: false,
   187  				Baz: []string{"def", "ghi"},
   188  			},
   189  		},
   190  	},
   191  
   192  	{
   193  		input: `
   194  			m {
   195  				nested: {
   196  					foo: "abc",
   197  				},
   198  				bar: false,
   199  				baz: ["def", "ghi"],
   200  			}
   201  		`,
   202  		output: []interface{}{
   203  			struct {
   204  				Nested struct {
   205  					Foo string `allowNested:"true"`
   206  				} `blueprint:"filter(allowNested:\"true\")"`
   207  				Bar bool
   208  				Baz []string
   209  			}{
   210  				Nested: struct {
   211  					Foo string `allowNested:"true"`
   212  				}{
   213  					Foo: "abc",
   214  				},
   215  				Bar: false,
   216  				Baz: []string{"def", "ghi"},
   217  			},
   218  		},
   219  	},
   220  
   221  	{
   222  		input: `
   223  			m {
   224  				nested: {
   225  					foo: "abc",
   226  				},
   227  				bar: false,
   228  				baz: ["def", "ghi"],
   229  			}
   230  		`,
   231  		output: []interface{}{
   232  			struct {
   233  				Nested struct {
   234  					Foo string
   235  				} `blueprint:"filter(allowNested:\"true\")"`
   236  				Bar bool
   237  				Baz []string
   238  			}{
   239  				Nested: struct{ Foo string }{
   240  					Foo: "",
   241  				},
   242  				Bar: false,
   243  				Baz: []string{"def", "ghi"},
   244  			},
   245  		},
   246  		errs: []error{
   247  			&BlueprintError{
   248  				Err: fmt.Errorf("filtered field nested.foo cannot be set in a Blueprint file"),
   249  				Pos: mkpos(30, 4, 9),
   250  			},
   251  		},
   252  	},
   253  
   254  	// Anonymous struct
   255  	{
   256  		input: `
   257  			m {
   258  				name: "abc",
   259  				nested: {
   260  					name: "def",
   261  				},
   262  			}
   263  		`,
   264  		output: []interface{}{
   265  			struct {
   266  				EmbeddedStruct
   267  				Nested struct {
   268  					EmbeddedStruct
   269  				}
   270  			}{
   271  				EmbeddedStruct: EmbeddedStruct{
   272  					Name: "abc",
   273  				},
   274  				Nested: struct {
   275  					EmbeddedStruct
   276  				}{
   277  					EmbeddedStruct: EmbeddedStruct{
   278  						Name: "def",
   279  					},
   280  				},
   281  			},
   282  		},
   283  	},
   284  
   285  	// Anonymous interface
   286  	{
   287  		input: `
   288  			m {
   289  				name: "abc",
   290  				nested: {
   291  					name: "def",
   292  				},
   293  			}
   294  		`,
   295  		output: []interface{}{
   296  			struct {
   297  				EmbeddedInterface
   298  				Nested struct {
   299  					EmbeddedInterface
   300  				}
   301  			}{
   302  				EmbeddedInterface: &struct{ Name string }{
   303  					Name: "abc",
   304  				},
   305  				Nested: struct {
   306  					EmbeddedInterface
   307  				}{
   308  					EmbeddedInterface: &struct{ Name string }{
   309  						Name: "def",
   310  					},
   311  				},
   312  			},
   313  		},
   314  	},
   315  
   316  	// Anonymous struct with name collision
   317  	{
   318  		input: `
   319  			m {
   320  				name: "abc",
   321  				nested: {
   322  					name: "def",
   323  				},
   324  			}
   325  		`,
   326  		output: []interface{}{
   327  			struct {
   328  				Name string
   329  				EmbeddedStruct
   330  				Nested struct {
   331  					Name string
   332  					EmbeddedStruct
   333  				}
   334  			}{
   335  				Name: "abc",
   336  				EmbeddedStruct: EmbeddedStruct{
   337  					Name: "abc",
   338  				},
   339  				Nested: struct {
   340  					Name string
   341  					EmbeddedStruct
   342  				}{
   343  					Name: "def",
   344  					EmbeddedStruct: EmbeddedStruct{
   345  						Name: "def",
   346  					},
   347  				},
   348  			},
   349  		},
   350  	},
   351  
   352  	// Anonymous interface with name collision
   353  	{
   354  		input: `
   355  			m {
   356  				name: "abc",
   357  				nested: {
   358  					name: "def",
   359  				},
   360  			}
   361  		`,
   362  		output: []interface{}{
   363  			struct {
   364  				Name string
   365  				EmbeddedInterface
   366  				Nested struct {
   367  					Name string
   368  					EmbeddedInterface
   369  				}
   370  			}{
   371  				Name: "abc",
   372  				EmbeddedInterface: &struct{ Name string }{
   373  					Name: "abc",
   374  				},
   375  				Nested: struct {
   376  					Name string
   377  					EmbeddedInterface
   378  				}{
   379  					Name: "def",
   380  					EmbeddedInterface: &struct{ Name string }{
   381  						Name: "def",
   382  					},
   383  				},
   384  			},
   385  		},
   386  	},
   387  
   388  	// Variables
   389  	{
   390  		input: `
   391  			list = ["abc"]
   392  			string = "def"
   393  			list_with_variable = [string]
   394  			m {
   395  				name: string,
   396  				list: list,
   397  				list2: list_with_variable,
   398  			}
   399  		`,
   400  		output: []interface{}{
   401  			struct {
   402  				Name  string
   403  				List  []string
   404  				List2 []string
   405  			}{
   406  				Name:  "def",
   407  				List:  []string{"abc"},
   408  				List2: []string{"def"},
   409  			},
   410  		},
   411  	},
   412  
   413  	// Multiple property structs
   414  	{
   415  		input: `
   416  			m {
   417  				nested: {
   418  					name: "abc",
   419  				}
   420  			}
   421  		`,
   422  		output: []interface{}{
   423  			struct {
   424  				Nested struct {
   425  					Name string
   426  				}
   427  			}{
   428  				Nested: struct{ Name string }{
   429  					Name: "abc",
   430  				},
   431  			},
   432  			struct {
   433  				Nested struct {
   434  					Name string
   435  				}
   436  			}{
   437  				Nested: struct{ Name string }{
   438  					Name: "abc",
   439  				},
   440  			},
   441  			struct {
   442  			}{},
   443  		},
   444  	},
   445  
   446  	// Nil pointer to struct
   447  	{
   448  		input: `
   449  			m {
   450  				nested: {
   451  					name: "abc",
   452  				}
   453  			}
   454  		`,
   455  		output: []interface{}{
   456  			struct {
   457  				Nested *struct {
   458  					Name string
   459  				}
   460  			}{
   461  				Nested: &struct{ Name string }{
   462  					Name: "abc",
   463  				},
   464  			},
   465  		},
   466  		empty: []interface{}{
   467  			&struct {
   468  				Nested *struct {
   469  					Name string
   470  				}
   471  			}{},
   472  		},
   473  	},
   474  
   475  	// Interface containing nil pointer to struct
   476  	{
   477  		input: `
   478  			m {
   479  				nested: {
   480  					name: "abc",
   481  				}
   482  			}
   483  		`,
   484  		output: []interface{}{
   485  			struct {
   486  				Nested interface{}
   487  			}{
   488  				Nested: &EmbeddedStruct{
   489  					Name: "abc",
   490  				},
   491  			},
   492  		},
   493  		empty: []interface{}{
   494  			&struct {
   495  				Nested interface{}
   496  			}{
   497  				Nested: (*EmbeddedStruct)(nil),
   498  			},
   499  		},
   500  	},
   501  
   502  	// Factory set properties
   503  	{
   504  		input: `
   505  			m {
   506  				string: "abc",
   507  				string_ptr: "abc",
   508  				bool: false,
   509  				bool_ptr: false,
   510  				list: ["a", "b", "c"],
   511  			}
   512  		`,
   513  		output: []interface{}{
   514  			struct {
   515  				String     string
   516  				String_ptr *string
   517  				Bool       bool
   518  				Bool_ptr   *bool
   519  				List       []string
   520  			}{
   521  				String:     "012abc",
   522  				String_ptr: proptools.StringPtr("abc"),
   523  				Bool:       true,
   524  				Bool_ptr:   proptools.BoolPtr(false),
   525  				List:       []string{"0", "1", "2", "a", "b", "c"},
   526  			},
   527  		},
   528  		empty: []interface{}{
   529  			&struct {
   530  				String     string
   531  				String_ptr *string
   532  				Bool       bool
   533  				Bool_ptr   *bool
   534  				List       []string
   535  			}{
   536  				String:     "012",
   537  				String_ptr: proptools.StringPtr("012"),
   538  				Bool:       true,
   539  				Bool_ptr:   proptools.BoolPtr(true),
   540  				List:       []string{"0", "1", "2"},
   541  			},
   542  		},
   543  	},
   544  }
   545  
   546  type EmbeddedStruct struct{ Name string }
   547  type EmbeddedInterface interface{}
   548  
   549  func TestUnpackProperties(t *testing.T) {
   550  	for _, testCase := range validUnpackTestCases {
   551  		r := bytes.NewBufferString(testCase.input)
   552  		file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
   553  		if len(errs) != 0 {
   554  			t.Errorf("test case: %s", testCase.input)
   555  			t.Errorf("unexpected parse errors:")
   556  			for _, err := range errs {
   557  				t.Errorf("  %s", err)
   558  			}
   559  			t.FailNow()
   560  		}
   561  
   562  		for _, def := range file.Defs {
   563  			module, ok := def.(*parser.Module)
   564  			if !ok {
   565  				continue
   566  			}
   567  
   568  			var output []interface{}
   569  			if len(testCase.empty) > 0 {
   570  				output = testCase.empty
   571  			} else {
   572  				for _, p := range testCase.output {
   573  					output = append(output, proptools.CloneEmptyProperties(reflect.ValueOf(p)).Interface())
   574  				}
   575  			}
   576  			_, errs = unpackProperties(module.Properties, output...)
   577  			if len(errs) != 0 && len(testCase.errs) == 0 {
   578  				t.Errorf("test case: %s", testCase.input)
   579  				t.Errorf("unexpected unpack errors:")
   580  				for _, err := range errs {
   581  					t.Errorf("  %s", err)
   582  				}
   583  				t.FailNow()
   584  			} else if !reflect.DeepEqual(errs, testCase.errs) {
   585  				t.Errorf("test case: %s", testCase.input)
   586  				t.Errorf("incorrect errors:")
   587  				t.Errorf("  expected: %+v", testCase.errs)
   588  				t.Errorf("       got: %+v", errs)
   589  			}
   590  
   591  			if len(output) != len(testCase.output) {
   592  				t.Fatalf("incorrect number of property structs, expected %d got %d",
   593  					len(testCase.output), len(output))
   594  			}
   595  
   596  			for i := range output {
   597  				got := reflect.ValueOf(output[i]).Elem().Interface()
   598  				if !reflect.DeepEqual(got, testCase.output[i]) {
   599  					t.Errorf("test case: %s", testCase.input)
   600  					t.Errorf("incorrect output:")
   601  					t.Errorf("  expected: %+v", testCase.output[i])
   602  					t.Errorf("       got: %+v", got)
   603  				}
   604  			}
   605  		}
   606  	}
   607  }
   608  
   609  func mkpos(offset, line, column int) scanner.Position {
   610  	return scanner.Position{
   611  		Offset: offset,
   612  		Line:   line,
   613  		Column: column,
   614  	}
   615  }