...

Source file src/github.com/drone/envsubst/v2/parse/parse_test.go

Documentation: github.com/drone/envsubst/v2/parse

     1  package parse
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/go-cmp/cmp"
     7  )
     8  
     9  var tests = []struct {
    10  	Text string
    11  	Node Node
    12  }{
    13  
    14  	//
    15  	// text only
    16  	//
    17  	{
    18  		Text: "text",
    19  		Node: &TextNode{Value: "text"},
    20  	},
    21  	{
    22  		Text: "}text",
    23  		Node: &TextNode{Value: "}text"},
    24  	},
    25  	{
    26  		Text: "http://github.com",
    27  		Node: &TextNode{Value: "http://github.com"}, // should not escape double slash
    28  	},
    29  	{
    30  		Text: "$${string}",
    31  		Node: &TextNode{Value: "${string}"}, // should not escape double dollar
    32  	},
    33  	{
    34  		Text: "$$string",
    35  		Node: &TextNode{Value: "$string"}, // should not escape double dollar
    36  	},
    37  	{
    38  		Text: `\\.\pipe\pipename`,
    39  		Node: &TextNode{Value: `\\.\pipe\pipename`},
    40  	},
    41  
    42  	//
    43  	// variable only
    44  	//
    45  	{
    46  		Text: "${string}",
    47  		Node: &FuncNode{Param: "string"},
    48  	},
    49  
    50  	//
    51  	// text transform functions
    52  	//
    53  	{
    54  		Text: "${string,}",
    55  		Node: &FuncNode{
    56  			Param: "string",
    57  			Name:  ",",
    58  			Args:  nil,
    59  		},
    60  	},
    61  	{
    62  		Text: "${string,,}",
    63  		Node: &FuncNode{
    64  			Param: "string",
    65  			Name:  ",,",
    66  			Args:  nil,
    67  		},
    68  	},
    69  	{
    70  		Text: "${string^}",
    71  		Node: &FuncNode{
    72  			Param: "string",
    73  			Name:  "^",
    74  			Args:  nil,
    75  		},
    76  	},
    77  	{
    78  		Text: "${string^^}",
    79  		Node: &FuncNode{
    80  			Param: "string",
    81  			Name:  "^^",
    82  			Args:  nil,
    83  		},
    84  	},
    85  
    86  	//
    87  	// substring functions
    88  	//
    89  	{
    90  		Text: "${string:position}",
    91  		Node: &FuncNode{
    92  			Param: "string",
    93  			Name:  ":",
    94  			Args: []Node{
    95  				&TextNode{Value: "position"},
    96  			},
    97  		},
    98  	},
    99  	{
   100  		Text: "${string:position:length}",
   101  		Node: &FuncNode{
   102  			Param: "string",
   103  			Name:  ":",
   104  			Args: []Node{
   105  				&TextNode{Value: "position"},
   106  				&TextNode{Value: "length"},
   107  			},
   108  		},
   109  	},
   110  
   111  	//
   112  	// string removal functions
   113  	//
   114  	{
   115  		Text: "${string#substring}",
   116  		Node: &FuncNode{
   117  			Param: "string",
   118  			Name:  "#",
   119  			Args: []Node{
   120  				&TextNode{Value: "substring"},
   121  			},
   122  		},
   123  	},
   124  	{
   125  		Text: "${string##substring}",
   126  		Node: &FuncNode{
   127  			Param: "string",
   128  			Name:  "##",
   129  			Args: []Node{
   130  				&TextNode{Value: "substring"},
   131  			},
   132  		},
   133  	},
   134  	{
   135  		Text: "${string%substring}",
   136  		Node: &FuncNode{
   137  			Param: "string",
   138  			Name:  "%",
   139  			Args: []Node{
   140  				&TextNode{Value: "substring"},
   141  			},
   142  		},
   143  	},
   144  	{
   145  		Text: "${string%%substring}",
   146  		Node: &FuncNode{
   147  			Param: "string",
   148  			Name:  "%%",
   149  			Args: []Node{
   150  				&TextNode{Value: "substring"},
   151  			},
   152  		},
   153  	},
   154  
   155  	//
   156  	// string replace functions
   157  	//
   158  	{
   159  		Text: "${string/substring/replacement}",
   160  		Node: &FuncNode{
   161  			Param: "string",
   162  			Name:  "/",
   163  			Args: []Node{
   164  				&TextNode{Value: "substring"},
   165  				&TextNode{Value: "replacement"},
   166  			},
   167  		},
   168  	},
   169  	{
   170  		Text: "${string//substring/replacement}",
   171  		Node: &FuncNode{
   172  			Param: "string",
   173  			Name:  "//",
   174  			Args: []Node{
   175  				&TextNode{Value: "substring"},
   176  				&TextNode{Value: "replacement"},
   177  			},
   178  		},
   179  	},
   180  	{
   181  		Text: "${string/#substring/replacement}",
   182  		Node: &FuncNode{
   183  			Param: "string",
   184  			Name:  "/#",
   185  			Args: []Node{
   186  				&TextNode{Value: "substring"},
   187  				&TextNode{Value: "replacement"},
   188  			},
   189  		},
   190  	},
   191  	{
   192  		Text: "${string/%substring/replacement}",
   193  		Node: &FuncNode{
   194  			Param: "string",
   195  			Name:  "/%",
   196  			Args: []Node{
   197  				&TextNode{Value: "substring"},
   198  				&TextNode{Value: "replacement"},
   199  			},
   200  		},
   201  	},
   202  
   203  	//
   204  	// default value functions
   205  	//
   206  	{
   207  		Text: "${string=default}",
   208  		Node: &FuncNode{
   209  			Param: "string",
   210  			Name:  "=",
   211  			Args: []Node{
   212  				&TextNode{Value: "default"},
   213  			},
   214  		},
   215  	},
   216  	{
   217  		Text: "${string:=default}",
   218  		Node: &FuncNode{
   219  			Param: "string",
   220  			Name:  ":=",
   221  			Args: []Node{
   222  				&TextNode{Value: "default"},
   223  			},
   224  		},
   225  	},
   226  	{
   227  		Text: "${string:-default}",
   228  		Node: &FuncNode{
   229  			Param: "string",
   230  			Name:  ":-",
   231  			Args: []Node{
   232  				&TextNode{Value: "default"},
   233  			},
   234  		},
   235  	},
   236  	{
   237  		Text: "${string:?default}",
   238  		Node: &FuncNode{
   239  			Param: "string",
   240  			Name:  ":?",
   241  			Args: []Node{
   242  				&TextNode{Value: "default"},
   243  			},
   244  		},
   245  	},
   246  	{
   247  		Text: "${string:+default}",
   248  		Node: &FuncNode{
   249  			Param: "string",
   250  			Name:  ":+",
   251  			Args: []Node{
   252  				&TextNode{Value: "default"},
   253  			},
   254  		},
   255  	},
   256  
   257  	//
   258  	// length function
   259  	//
   260  	{
   261  		Text: "${#string}",
   262  		Node: &FuncNode{
   263  			Param: "string",
   264  			Name:  "#",
   265  		},
   266  	},
   267  
   268  	//
   269  	// special characters in argument
   270  	//
   271  	{
   272  		Text: "${string#$%:*{}",
   273  		Node: &FuncNode{
   274  			Param: "string",
   275  			Name:  "#",
   276  			Args: []Node{
   277  				&TextNode{Value: "$%:*{"},
   278  			},
   279  		},
   280  	},
   281  
   282  	// text before and after function
   283  	{
   284  		Text: "hello ${#string} world",
   285  		Node: &ListNode{
   286  			Nodes: []Node{
   287  				&TextNode{
   288  					Value: "hello ",
   289  				},
   290  				&ListNode{
   291  					Nodes: []Node{
   292  						&FuncNode{
   293  							Param: "string",
   294  							Name:  "#",
   295  						},
   296  						&TextNode{
   297  							Value: " world",
   298  						},
   299  					},
   300  				},
   301  			},
   302  		},
   303  	},
   304  	// text before and after function with \\ outside of function
   305  	{
   306  		Text: `\\ hello ${#string} world \\`,
   307  		Node: &ListNode{
   308  			Nodes: []Node{
   309  				&TextNode{
   310  					Value: `\\ hello `,
   311  				},
   312  				&ListNode{
   313  					Nodes: []Node{
   314  						&FuncNode{
   315  							Param: "string",
   316  							Name:  "#",
   317  						},
   318  						&TextNode{
   319  							Value: ` world \\`,
   320  						},
   321  					},
   322  				},
   323  			},
   324  		},
   325  	},
   326  
   327  	// escaped function arguments
   328  	{
   329  		Text: `${string/\/position/length}`,
   330  		Node: &FuncNode{
   331  			Param: "string",
   332  			Name:  "/",
   333  			Args: []Node{
   334  				&TextNode{
   335  					Value: "/position",
   336  				},
   337  				&TextNode{
   338  					Value: "length",
   339  				},
   340  			},
   341  		},
   342  	},
   343  	{
   344  		Text: `${string/\/position\\/length}`,
   345  		Node: &FuncNode{
   346  			Param: "string",
   347  			Name:  "/",
   348  			Args: []Node{
   349  				&TextNode{
   350  					Value: "/position\\",
   351  				},
   352  				&TextNode{
   353  					Value: "length",
   354  				},
   355  			},
   356  		},
   357  	},
   358  	{
   359  		Text: `${string/position/\/length}`,
   360  		Node: &FuncNode{
   361  			Param: "string",
   362  			Name:  "/",
   363  			Args: []Node{
   364  				&TextNode{
   365  					Value: "position",
   366  				},
   367  				&TextNode{
   368  					Value: "/length",
   369  				},
   370  			},
   371  		},
   372  	},
   373  	{
   374  		Text: `${string/position/\/length\\}`,
   375  		Node: &FuncNode{
   376  			Param: "string",
   377  			Name:  "/",
   378  			Args: []Node{
   379  				&TextNode{
   380  					Value: "position",
   381  				},
   382  				&TextNode{
   383  					Value: "/length\\",
   384  				},
   385  			},
   386  		},
   387  	},
   388  	{
   389  		Text: `${string/position/\/leng\\th}`,
   390  		Node: &FuncNode{
   391  			Param: "string",
   392  			Name:  "/",
   393  			Args: []Node{
   394  				&TextNode{
   395  					Value: "position",
   396  				},
   397  				&TextNode{
   398  					Value: "/leng\\th",
   399  				},
   400  			},
   401  		},
   402  	},
   403  
   404  	// functions in functions
   405  	{
   406  		Text: "${string:${position}}",
   407  		Node: &FuncNode{
   408  			Param: "string",
   409  			Name:  ":",
   410  			Args: []Node{
   411  				&FuncNode{
   412  					Param: "position",
   413  				},
   414  			},
   415  		},
   416  	},
   417  	{
   418  		Text: "${string:${stringy:position:length}:${stringz,,}}",
   419  		Node: &FuncNode{
   420  			Param: "string",
   421  			Name:  ":",
   422  			Args: []Node{
   423  				&FuncNode{
   424  					Param: "stringy",
   425  					Name:  ":",
   426  					Args: []Node{
   427  						&TextNode{Value: "position"},
   428  						&TextNode{Value: "length"},
   429  					},
   430  				},
   431  				&FuncNode{
   432  					Param: "stringz",
   433  					Name:  ",,",
   434  				},
   435  			},
   436  		},
   437  	},
   438  	{
   439  		Text: "${string#${stringz}}",
   440  		Node: &FuncNode{
   441  			Param: "string",
   442  			Name:  "#",
   443  			Args: []Node{
   444  				&FuncNode{Param: "stringz"},
   445  			},
   446  		},
   447  	},
   448  	{
   449  		Text: "${string=${stringz}}",
   450  		Node: &FuncNode{
   451  			Param: "string",
   452  			Name:  "=",
   453  			Args: []Node{
   454  				&FuncNode{Param: "stringz"},
   455  			},
   456  		},
   457  	},
   458  	{
   459  		Text: "${string=prefix-${var}}",
   460  		Node: &FuncNode{
   461  			Param: "string",
   462  			Name:  "=",
   463  			Args: []Node{
   464  				&TextNode{Value: "prefix-"},
   465  				&FuncNode{Param: "var"},
   466  			},
   467  		},
   468  	},
   469  	{
   470  		Text: "${string=${var}-suffix}",
   471  		Node: &FuncNode{
   472  			Param: "string",
   473  			Name:  "=",
   474  			Args: []Node{
   475  				&FuncNode{Param: "var"},
   476  				&TextNode{Value: "-suffix"},
   477  			},
   478  		},
   479  	},
   480  	{
   481  		Text: "${string=prefix-${var}-suffix}",
   482  		Node: &FuncNode{
   483  			Param: "string",
   484  			Name:  "=",
   485  			Args: []Node{
   486  				&TextNode{Value: "prefix-"},
   487  				&FuncNode{Param: "var"},
   488  				&TextNode{Value: "-suffix"},
   489  			},
   490  		},
   491  	},
   492  	{
   493  		Text: "${string=prefix${var} suffix}",
   494  		Node: &FuncNode{
   495  			Param: "string",
   496  			Name:  "=",
   497  			Args: []Node{
   498  				&TextNode{Value: "prefix"},
   499  				&FuncNode{Param: "var"},
   500  				&TextNode{Value: " suffix"},
   501  			},
   502  		},
   503  	},
   504  	{
   505  		Text: "${string//${stringy}/${stringz}}",
   506  		Node: &FuncNode{
   507  			Param: "string",
   508  			Name:  "//",
   509  			Args: []Node{
   510  				&FuncNode{Param: "stringy"},
   511  				&FuncNode{Param: "stringz"},
   512  			},
   513  		},
   514  	},
   515  }
   516  
   517  func TestParse(t *testing.T) {
   518  	for _, test := range tests {
   519  		t.Log(test.Text)
   520  		t.Run(test.Text, func(t *testing.T) {
   521  			got, err := Parse(test.Text)
   522  			if err != nil {
   523  				t.Error(err)
   524  			}
   525  
   526  			if diff := cmp.Diff(test.Node, got.Root); diff != "" {
   527  				t.Errorf(diff)
   528  			}
   529  		})
   530  	}
   531  }
   532  

View as plain text