...

Source file src/github.com/protocolbuffers/txtpbfmt/ast/ast_test.go

Documentation: github.com/protocolbuffers/txtpbfmt/ast

     1  package ast_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/go-cmp/cmp"
     7  	"github.com/kylelemons/godebug/diff"
     8  	"github.com/protocolbuffers/txtpbfmt/ast"
     9  	"github.com/protocolbuffers/txtpbfmt/parser"
    10  )
    11  
    12  func TestChainNodeLess(t *testing.T) {
    13  	byFirstChar := func(_, ni, nj *ast.Node, isWholeSlice bool) bool {
    14  		return ni.Name[0] < nj.Name[0]
    15  	}
    16  	bySecondChar := func(_, ni, nj *ast.Node, isWholeSlice bool) bool {
    17  		return ni.Name[1] < nj.Name[1]
    18  	}
    19  	tests := []struct {
    20  		name  string
    21  		a     ast.NodeLess
    22  		b     ast.NodeLess
    23  		names []string
    24  		want  []string
    25  	}{{
    26  		name:  "nil + byFirstChar",
    27  		a:     nil,
    28  		b:     byFirstChar,
    29  		names: []string{"c", "b", "z", "a"},
    30  		want:  []string{"a", "b", "c", "z"},
    31  	}, {
    32  		name:  "byFirstChar + nil",
    33  		a:     nil,
    34  		b:     byFirstChar,
    35  		names: []string{"c", "b", "z", "a"},
    36  		want:  []string{"a", "b", "c", "z"},
    37  	}, {
    38  		name:  "byFirstChar + bySecondChar",
    39  		a:     byFirstChar,
    40  		b:     bySecondChar,
    41  		names: []string{"zc", "bb", "za", "aa", "ac", "ba", "bc", "ab", "zb"},
    42  		want:  []string{"aa", "ab", "ac", "ba", "bb", "bc", "za", "zb", "zc"},
    43  	}, {
    44  		name:  "bySecondChar + byFirstChar",
    45  		a:     bySecondChar,
    46  		b:     byFirstChar,
    47  		names: []string{"zc", "bb", "za", "aa", "ac", "ba", "bc", "ab", "zb"},
    48  		want:  []string{"aa", "ba", "za", "ab", "bb", "zb", "ac", "bc", "zc"},
    49  	}}
    50  	// Map strings into Node names, sort Nodes, map Node names into strings, return sorted names.
    51  	sortNames := func(names []string, less ast.NodeLess) []string {
    52  		ns := []*ast.Node{}
    53  		for _, n := range names {
    54  			ns = append(ns, &ast.Node{Name: n})
    55  		}
    56  		ast.SortNodes(nil /* parent */, ns, less)
    57  		rs := []string{}
    58  		for _, n := range ns {
    59  			rs = append(rs, n.Name)
    60  		}
    61  		return rs
    62  	}
    63  	for _, tc := range tests {
    64  		less := ast.ChainNodeLess(tc.a, tc.b)
    65  		got := sortNames(tc.names, less)
    66  		if diff := cmp.Diff(tc.want, got); diff != "" {
    67  			t.Errorf("%s sorting %v returned diff (-want, +got):\n%s", tc.name, tc.names, diff)
    68  		}
    69  	}
    70  }
    71  
    72  func TestGetFromPath(t *testing.T) {
    73  	content := `first {
    74    second {
    75      third: "v1"
    76      third: "v2"
    77    }
    78    second {
    79      third: "v3"
    80      third: "v4"
    81    }
    82  }
    83  first {
    84    second {
    85      third: "v5"
    86      third: "v6"
    87    }
    88    second {
    89      third: "v7"
    90      third: "v8"
    91    }
    92  }
    93  `
    94  	inputs := []struct {
    95  		in   string
    96  		path []string
    97  		want string
    98  	}{{
    99  		in:   content,
   100  		path: nil,
   101  		want: ``,
   102  	}, {
   103  		in:   content,
   104  		path: []string{"first", "second", "third"},
   105  		want: `third: "v1"
   106  third: "v2"
   107  third: "v3"
   108  third: "v4"
   109  third: "v5"
   110  third: "v6"
   111  third: "v7"
   112  third: "v8"
   113  `,
   114  	}, {
   115  		in:   content,
   116  		path: []string{"first", "second"},
   117  		want: `second {
   118    third: "v1"
   119    third: "v2"
   120  }
   121  second {
   122    third: "v3"
   123    third: "v4"
   124  }
   125  second {
   126    third: "v5"
   127    third: "v6"
   128  }
   129  second {
   130    third: "v7"
   131    third: "v8"
   132  }
   133  `,
   134  	}, {
   135  		in:   content,
   136  		path: []string{"first"},
   137  		want: content,
   138  	}}
   139  	for _, input := range inputs {
   140  		nodes, err := parser.Parse([]byte(input.in))
   141  		if err != nil {
   142  			t.Errorf("Parse %v returned err %v", input.in, err)
   143  			continue
   144  		}
   145  		filtered := ast.GetFromPath(nodes, input.path)
   146  		got := parser.Pretty(filtered, 0)
   147  		if diff := diff.Diff(input.want, got); diff != "" {
   148  			t.Errorf("GetFromPath %v %v returned diff (-want, +got):\n%s", input.in, input.path, diff)
   149  		}
   150  	}
   151  }
   152  
   153  func TestIsCommentOnly(t *testing.T) {
   154  	inputs := []struct {
   155  		in   string
   156  		want []bool
   157  	}{{
   158  		in: `foo: 1
   159  bar: 2`,
   160  		want: []bool{false, false},
   161  	},
   162  		{
   163  			in: `foo: 1
   164  bar: 2
   165  `,
   166  			want: []bool{false, false},
   167  		},
   168  		{
   169  			in: `foo: 1
   170  bar: 2
   171  # A long trailing comment
   172  # over multiple lines.
   173  `,
   174  			want: []bool{false, false, true},
   175  		},
   176  		{
   177  			in: `first {
   178    foo: true  # bar
   179  }
   180  `,
   181  			want: []bool{false},
   182  		},
   183  		{
   184  			in: `first {
   185    foo: true  # bar
   186  }
   187  # trailing comment
   188  `,
   189  			want: []bool{false, true},
   190  		},
   191  		{
   192  			in:   `{}`,
   193  			want: []bool{false},
   194  		},
   195  	}
   196  	for _, input := range inputs {
   197  		nodes, err := parser.Parse([]byte(input.in))
   198  		if err != nil {
   199  			t.Errorf("Parse %v returned err %v", input.in, err)
   200  			continue
   201  		}
   202  		if len(nodes) != len(input.want) {
   203  			t.Errorf("For %v, expect %v nodes, got %v", input.in, len(input.want), len(nodes))
   204  		}
   205  		for i, n := range nodes {
   206  			if got := n.IsCommentOnly(); got != input.want[i] {
   207  				t.Errorf("For %v, nodes[%v].IsCommentOnly() = %v, want %v", input.in, i, got, input.want[i])
   208  			}
   209  		}
   210  	}
   211  }
   212  
   213  func TestFixInline(t *testing.T) {
   214  	content := `first { }`
   215  
   216  	inputs := []struct {
   217  		in   string
   218  		add  string
   219  		want string
   220  	}{{
   221  		in:  content,
   222  		add: "foo: true  # bar",
   223  		want: `first {
   224    foo: true  # bar
   225  }
   226  `,
   227  	}, {
   228  		in: content,
   229  		add: `
   230  			# bar
   231  			foo: true`,
   232  		want: `first {
   233    # bar
   234    foo: true
   235  }
   236  `,
   237  	}, {
   238  		in: content,
   239  		add: `
   240  			# bar
   241  			foo: true  # baz`,
   242  		want: `first {
   243    # bar
   244    foo: true  # baz
   245  }
   246  `,
   247  	}, {
   248  		in: content,
   249  		add: `
   250  			foo {
   251  				bar: true
   252  			}`,
   253  		want: `first {
   254    foo {
   255      bar: true
   256    }
   257  }
   258  `,
   259  	}, {
   260  		in:  content,
   261  		add: `foo { bar: { baz: true } zip: "foo" }`,
   262  		want: `first { foo { bar: { baz: true } zip: "foo" } }
   263  `,
   264  	}, {in: `foo {}`, add: ``, want: `foo {}
   265  `}, {in: `foo {
   266  }`, add: ``, want: `foo {
   267  }
   268  `}, {in: `foo <>`, add: ``, want: `foo {}
   269  `}, {in: `foo {
   270    bar: [
   271      1,
   272      2
   273    ]
   274  }`, add: ``, want: `foo {
   275    bar: [
   276      1,
   277      2
   278    ]
   279  }
   280  `}}
   281  	for _, input := range inputs {
   282  		nodes, err := parser.Parse([]byte(input.in))
   283  		if err != nil {
   284  			t.Errorf("Parse %v returned err %v", input.in, err)
   285  			continue
   286  		}
   287  		if len(nodes) == 0 {
   288  			t.Errorf("Parse %v returned no nodes", input.in)
   289  			continue
   290  		}
   291  		if input.add != "" {
   292  			add, err := parser.Parse([]byte(input.add))
   293  			if err != nil {
   294  				t.Errorf("Parse %v returned err %v", input.in, err)
   295  				continue
   296  			}
   297  			nodes[0].Children = add
   298  		}
   299  		nodes[0].Fix()
   300  		got := parser.Pretty(nodes, 0)
   301  		if diff := diff.Diff(input.want, got); diff != "" {
   302  			t.Errorf("adding %v %v returned diff (-want, +got):\n%s", input.in, input.add, diff)
   303  		}
   304  	}
   305  }
   306  
   307  func TestListSyntax(t *testing.T) {
   308  	// A comparer that ignores ast.Position fields so as to simplify writing our nodes without including position information.
   309  	ignoreAstPositionComparer := cmp.Comparer(func(x, y ast.Position) bool {
   310  		return true
   311  	})
   312  
   313  	inputs := []struct {
   314  		in   string
   315  		want []*ast.Node
   316  	}{{
   317  		in: `foo: []`,
   318  		want: []*ast.Node{&ast.Node{
   319  			Name:             "foo",
   320  			ChildrenSameLine: true,
   321  			ValuesAsList:     true}},
   322  	}, {
   323  		in: `foo: [
   324  			{
   325  				field: val1,
   326  				other_field: val2
   327  			},
   328  			{
   329  				field: val3,
   330  			}
   331  	]`,
   332  		want: []*ast.Node{&ast.Node{
   333  			Name:           "foo",
   334  			ChildrenAsList: true,
   335  			Children: []*ast.Node{
   336  				&ast.Node{
   337  					Name:      "",
   338  					SkipColon: true,
   339  					Children: []*ast.Node{
   340  						&ast.Node{Name: "field", Values: []*ast.Value{&ast.Value{Value: "val1"}}},
   341  						&ast.Node{Name: "other_field", Values: []*ast.Value{&ast.Value{Value: "val2"}}},
   342  					},
   343  				},
   344  				&ast.Node{
   345  					Name:      "",
   346  					SkipColon: true,
   347  					Children: []*ast.Node{
   348  						&ast.Node{Name: "field", Values: []*ast.Value{&ast.Value{Value: "val3"}}},
   349  					},
   350  				},
   351  			}}},
   352  	}, {
   353  		in: `foo: {
   354  				field: val1,
   355  				other_field: val2
   356  			}
   357  			foo: {
   358  				field: val3,
   359  			}`,
   360  		want: []*ast.Node{
   361  			&ast.Node{
   362  				Name: "foo",
   363  				Children: []*ast.Node{
   364  					&ast.Node{Name: "field", Values: []*ast.Value{&ast.Value{Value: "val1"}}},
   365  					&ast.Node{Name: "other_field", Values: []*ast.Value{&ast.Value{Value: "val2"}}},
   366  				},
   367  			},
   368  			&ast.Node{
   369  				Name: "foo",
   370  				Children: []*ast.Node{
   371  					&ast.Node{
   372  						Name:   "field",
   373  						Values: []*ast.Value{&ast.Value{Value: "val3"}},
   374  					},
   375  				},
   376  			}},
   377  	},
   378  	}
   379  	for _, input := range inputs {
   380  		nodes, err := parser.Parse([]byte(input.in))
   381  		if err != nil {
   382  			t.Errorf("Parse returned err %v", err)
   383  			continue
   384  		}
   385  		if diff := cmp.Diff(input.want, nodes, ignoreAstPositionComparer); diff != "" {
   386  			t.Errorf("Parse() returned unexpected difference in parsed nodes (-want +got):\n%s", diff)
   387  		}
   388  	}
   389  }
   390  

View as plain text