...

Source file src/github.com/hashicorp/hcl/json/parser/parser_test.go

Documentation: github.com/hashicorp/hcl/json/parser

     1  package parser
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"path/filepath"
     7  	"reflect"
     8  	"runtime"
     9  	"testing"
    10  
    11  	"github.com/hashicorp/hcl/hcl/ast"
    12  	"github.com/hashicorp/hcl/hcl/token"
    13  )
    14  
    15  func TestType(t *testing.T) {
    16  	var literals = []struct {
    17  		typ token.Type
    18  		src string
    19  	}{
    20  		{token.STRING, `"foo": "bar"`},
    21  		{token.NUMBER, `"foo": 123`},
    22  		{token.FLOAT, `"foo": 123.12`},
    23  		{token.FLOAT, `"foo": -123.12`},
    24  		{token.BOOL, `"foo": true`},
    25  		{token.STRING, `"foo": null`},
    26  	}
    27  
    28  	for _, l := range literals {
    29  		t.Logf("Testing: %s", l.src)
    30  
    31  		p := newParser([]byte(l.src))
    32  		item, err := p.objectItem()
    33  		if err != nil {
    34  			t.Error(err)
    35  		}
    36  
    37  		lit, ok := item.Val.(*ast.LiteralType)
    38  		if !ok {
    39  			t.Errorf("node should be of type LiteralType, got: %T", item.Val)
    40  		}
    41  
    42  		if lit.Token.Type != l.typ {
    43  			t.Errorf("want: %s, got: %s", l.typ, lit.Token.Type)
    44  		}
    45  	}
    46  }
    47  
    48  func TestListType(t *testing.T) {
    49  	var literals = []struct {
    50  		src    string
    51  		tokens []token.Type
    52  	}{
    53  		{
    54  			`"foo": ["123", 123]`,
    55  			[]token.Type{token.STRING, token.NUMBER},
    56  		},
    57  		{
    58  			`"foo": [123, "123",]`,
    59  			[]token.Type{token.NUMBER, token.STRING},
    60  		},
    61  		{
    62  			`"foo": []`,
    63  			[]token.Type{},
    64  		},
    65  		{
    66  			`"foo": ["123", 123]`,
    67  			[]token.Type{token.STRING, token.NUMBER},
    68  		},
    69  		{
    70  			`"foo": ["123", {}]`,
    71  			[]token.Type{token.STRING, token.LBRACE},
    72  		},
    73  	}
    74  
    75  	for _, l := range literals {
    76  		t.Logf("Testing: %s", l.src)
    77  
    78  		p := newParser([]byte(l.src))
    79  		item, err := p.objectItem()
    80  		if err != nil {
    81  			t.Error(err)
    82  		}
    83  
    84  		list, ok := item.Val.(*ast.ListType)
    85  		if !ok {
    86  			t.Errorf("node should be of type LiteralType, got: %T", item.Val)
    87  		}
    88  
    89  		tokens := []token.Type{}
    90  		for _, li := range list.List {
    91  			switch v := li.(type) {
    92  			case *ast.LiteralType:
    93  				tokens = append(tokens, v.Token.Type)
    94  			case *ast.ObjectType:
    95  				tokens = append(tokens, token.LBRACE)
    96  			}
    97  		}
    98  
    99  		equals(t, l.tokens, tokens)
   100  	}
   101  }
   102  
   103  func TestObjectType(t *testing.T) {
   104  	var literals = []struct {
   105  		src      string
   106  		nodeType []ast.Node
   107  		itemLen  int
   108  	}{
   109  		{
   110  			`"foo": {}`,
   111  			nil,
   112  			0,
   113  		},
   114  		{
   115  			`"foo": {
   116  				"bar": "fatih"
   117  			 }`,
   118  			[]ast.Node{&ast.LiteralType{}},
   119  			1,
   120  		},
   121  		{
   122  			`"foo": {
   123  				"bar": "fatih",
   124  				"baz": ["arslan"]
   125  			 }`,
   126  			[]ast.Node{
   127  				&ast.LiteralType{},
   128  				&ast.ListType{},
   129  			},
   130  			2,
   131  		},
   132  		{
   133  			`"foo": {
   134  				"bar": {}
   135  			 }`,
   136  			[]ast.Node{
   137  				&ast.ObjectType{},
   138  			},
   139  			1,
   140  		},
   141  		{
   142  			`"foo": {
   143  				"bar": {},
   144  				"foo": true
   145  			 }`,
   146  			[]ast.Node{
   147  				&ast.ObjectType{},
   148  				&ast.LiteralType{},
   149  			},
   150  			2,
   151  		},
   152  	}
   153  
   154  	for _, l := range literals {
   155  		t.Logf("Testing:\n%s\n", l.src)
   156  
   157  		p := newParser([]byte(l.src))
   158  		// p.enableTrace = true
   159  		item, err := p.objectItem()
   160  		if err != nil {
   161  			t.Error(err)
   162  		}
   163  
   164  		// we know that the ObjectKey name is foo for all cases, what matters
   165  		// is the object
   166  		obj, ok := item.Val.(*ast.ObjectType)
   167  		if !ok {
   168  			t.Errorf("node should be of type LiteralType, got: %T", item.Val)
   169  		}
   170  
   171  		// check if the total length of items are correct
   172  		equals(t, l.itemLen, len(obj.List.Items))
   173  
   174  		// check if the types are correct
   175  		for i, item := range obj.List.Items {
   176  			equals(t, reflect.TypeOf(l.nodeType[i]), reflect.TypeOf(item.Val))
   177  		}
   178  	}
   179  }
   180  
   181  func TestFlattenObjects(t *testing.T) {
   182  	var literals = []struct {
   183  		src      string
   184  		nodeType []ast.Node
   185  		itemLen  int
   186  	}{
   187  		{
   188  			`{
   189  					"foo": [
   190  						{
   191  							"foo": "svh",
   192  							"bar": "fatih"
   193  						}
   194  					]
   195  				}`,
   196  			[]ast.Node{
   197  				&ast.ObjectType{},
   198  				&ast.LiteralType{},
   199  				&ast.LiteralType{},
   200  			},
   201  			3,
   202  		},
   203  		{
   204  			`{
   205  					"variable": {
   206  						"foo": {}
   207  					}
   208  				}`,
   209  			[]ast.Node{
   210  				&ast.ObjectType{},
   211  			},
   212  			1,
   213  		},
   214  		{
   215  			`{
   216  				"empty": []
   217  			}`,
   218  			[]ast.Node{
   219  				&ast.ListType{},
   220  			},
   221  			1,
   222  		},
   223  		{
   224  			`{
   225  				"basic": [1, 2, 3]
   226  			}`,
   227  			[]ast.Node{
   228  				&ast.ListType{},
   229  			},
   230  			1,
   231  		},
   232  	}
   233  
   234  	for _, l := range literals {
   235  		t.Logf("Testing:\n%s\n", l.src)
   236  
   237  		f, err := Parse([]byte(l.src))
   238  		if err != nil {
   239  			t.Error(err)
   240  		}
   241  
   242  		// the first object is always an ObjectList so just assert that one
   243  		// so we can use it as such
   244  		obj, ok := f.Node.(*ast.ObjectList)
   245  		if !ok {
   246  			t.Errorf("node should be *ast.ObjectList, got: %T", f.Node)
   247  		}
   248  
   249  		// check if the types are correct
   250  		var i int
   251  		for _, item := range obj.Items {
   252  			equals(t, reflect.TypeOf(l.nodeType[i]), reflect.TypeOf(item.Val))
   253  			i++
   254  
   255  			if obj, ok := item.Val.(*ast.ObjectType); ok {
   256  				for _, item := range obj.List.Items {
   257  					equals(t, reflect.TypeOf(l.nodeType[i]), reflect.TypeOf(item.Val))
   258  					i++
   259  				}
   260  			}
   261  		}
   262  
   263  		// check if the number of items is correct
   264  		equals(t, l.itemLen, i)
   265  
   266  	}
   267  }
   268  
   269  func TestObjectKey(t *testing.T) {
   270  	keys := []struct {
   271  		exp []token.Type
   272  		src string
   273  	}{
   274  		{[]token.Type{token.STRING}, `"foo": {}`},
   275  	}
   276  
   277  	for _, k := range keys {
   278  		p := newParser([]byte(k.src))
   279  		keys, err := p.objectKey()
   280  		if err != nil {
   281  			t.Fatal(err)
   282  		}
   283  
   284  		tokens := []token.Type{}
   285  		for _, o := range keys {
   286  			tokens = append(tokens, o.Token.Type)
   287  		}
   288  
   289  		equals(t, k.exp, tokens)
   290  	}
   291  
   292  	errKeys := []struct {
   293  		src string
   294  	}{
   295  		{`foo 12 {}`},
   296  		{`foo bar = {}`},
   297  		{`foo []`},
   298  		{`12 {}`},
   299  	}
   300  
   301  	for _, k := range errKeys {
   302  		p := newParser([]byte(k.src))
   303  		_, err := p.objectKey()
   304  		if err == nil {
   305  			t.Errorf("case '%s' should give an error", k.src)
   306  		}
   307  	}
   308  }
   309  
   310  // Official HCL tests
   311  func TestParse(t *testing.T) {
   312  	cases := []struct {
   313  		Name string
   314  		Err  bool
   315  	}{
   316  		{
   317  			"array.json",
   318  			false,
   319  		},
   320  		{
   321  			"basic.json",
   322  			false,
   323  		},
   324  		{
   325  			"object.json",
   326  			false,
   327  		},
   328  		{
   329  			"types.json",
   330  			false,
   331  		},
   332  		{
   333  			"bad_input_128.json",
   334  			true,
   335  		},
   336  		{
   337  			"bad_input_tf_8110.json",
   338  			true,
   339  		},
   340  		{
   341  			"good_input_tf_8110.json",
   342  			false,
   343  		},
   344  	}
   345  
   346  	const fixtureDir = "./test-fixtures"
   347  
   348  	for _, tc := range cases {
   349  		d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.Name))
   350  		if err != nil {
   351  			t.Fatalf("err: %s", err)
   352  		}
   353  
   354  		_, err = Parse(d)
   355  		if (err != nil) != tc.Err {
   356  			t.Fatalf("Input: %s\n\nError: %s", tc.Name, err)
   357  		}
   358  	}
   359  }
   360  
   361  func TestParse_inline(t *testing.T) {
   362  	cases := []struct {
   363  		Value string
   364  		Err   bool
   365  	}{
   366  		{"{:{", true},
   367  	}
   368  
   369  	for _, tc := range cases {
   370  		_, err := Parse([]byte(tc.Value))
   371  		if (err != nil) != tc.Err {
   372  			t.Fatalf("Input: %q\n\nError: %s", tc.Value, err)
   373  		}
   374  	}
   375  }
   376  
   377  // equals fails the test if exp is not equal to act.
   378  func equals(tb testing.TB, exp, act interface{}) {
   379  	if !reflect.DeepEqual(exp, act) {
   380  		_, file, line, _ := runtime.Caller(1)
   381  		fmt.Printf("\033[31m%s:%d:\n\n\texp: %s\n\n\tgot: %s\033[39m\n\n", filepath.Base(file), line, exp, act)
   382  		tb.FailNow()
   383  	}
   384  }
   385  

View as plain text