Home | History | Annotate | Download | only in kati
      1 // Copyright 2015 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 kati
     16 
     17 import (
     18 	"reflect"
     19 	"testing"
     20 )
     21 
     22 func TestParseExpr(t *testing.T) {
     23 	for _, tc := range []struct {
     24 		in    string
     25 		val   Value
     26 		isErr bool
     27 	}{
     28 		{
     29 			in:  "foo",
     30 			val: literal("foo"),
     31 		},
     32 		{
     33 			in:  "(foo)",
     34 			val: literal("(foo)"),
     35 		},
     36 		{
     37 			in:  "{foo}",
     38 			val: literal("{foo}"),
     39 		},
     40 		{
     41 			in:  "$$",
     42 			val: literal("$"),
     43 		},
     44 		{
     45 			in:  "foo$$bar",
     46 			val: literal("foo$bar"),
     47 		},
     48 		{
     49 			in:  "$foo",
     50 			val: expr{&varref{varname: literal("f")}, literal("oo")},
     51 		},
     52 		{
     53 			in:  "$(foo)",
     54 			val: &varref{varname: literal("foo"), paren: '('},
     55 		},
     56 		{
     57 			in: "$(foo:.c=.o)",
     58 			val: varsubst{
     59 				varname: literal("foo"),
     60 				pat:     literal(".c"),
     61 				subst:   literal(".o"),
     62 				paren:   '(',
     63 			},
     64 		},
     65 		{
     66 			in: "$(subst $(space),$(,),$(foo))/bar",
     67 			val: expr{
     68 				&funcSubst{
     69 					fclosure: fclosure{
     70 						args: []Value{
     71 							literal("(subst"),
     72 							&varref{
     73 								varname: literal("space"),
     74 								paren:   '(',
     75 							},
     76 							&varref{
     77 								varname: literal(","),
     78 								paren:   '(',
     79 							},
     80 							&varref{
     81 								varname: literal("foo"),
     82 								paren:   '(',
     83 							},
     84 						},
     85 					},
     86 				},
     87 				literal("/bar"),
     88 			},
     89 		},
     90 		{
     91 			in: "$(subst $(space),$,,$(foo))",
     92 			val: &funcSubst{
     93 				fclosure: fclosure{
     94 					args: []Value{
     95 						literal("(subst"),
     96 						&varref{
     97 							varname: literal("space"),
     98 							paren:   '(',
     99 						},
    100 						&varref{
    101 							varname: literal(""),
    102 						},
    103 						expr{
    104 							literal(","),
    105 							&varref{
    106 								varname: literal("foo"),
    107 								paren:   '(',
    108 							},
    109 						},
    110 					},
    111 				},
    112 			},
    113 		},
    114 		{
    115 			in: `$(shell echo '()')`,
    116 			val: &funcShell{
    117 				fclosure: fclosure{
    118 					args: []Value{
    119 						literal("(shell"),
    120 						literal("echo '()'"),
    121 					},
    122 				},
    123 			},
    124 		},
    125 		{
    126 			in: `${shell echo '()'}`,
    127 			val: &funcShell{
    128 				fclosure: fclosure{
    129 					args: []Value{
    130 						literal("{shell"),
    131 						literal("echo '()'"),
    132 					},
    133 				},
    134 			},
    135 		},
    136 		{
    137 			in: `$(shell echo ')')`,
    138 			val: expr{
    139 				&funcShell{
    140 					fclosure: fclosure{
    141 						args: []Value{
    142 							literal("(shell"),
    143 							literal("echo '"),
    144 						},
    145 					},
    146 				},
    147 				literal("')"),
    148 			},
    149 		},
    150 		{
    151 			in: `${shell echo ')'}`,
    152 			val: &funcShell{
    153 				fclosure: fclosure{
    154 					args: []Value{
    155 						literal("{shell"),
    156 						literal("echo ')'"),
    157 					},
    158 				},
    159 			},
    160 		},
    161 		{
    162 			in: `${shell echo '}'}`,
    163 			val: expr{
    164 				&funcShell{
    165 					fclosure: fclosure{
    166 						args: []Value{
    167 							literal("{shell"),
    168 							literal("echo '"),
    169 						},
    170 					},
    171 				},
    172 				literal("'}"),
    173 			},
    174 		},
    175 		{
    176 			in: `$(shell make --version | ruby -n0e 'puts $$_[/Make (\d)/,1]')`,
    177 			val: &funcShell{
    178 				fclosure: fclosure{
    179 					args: []Value{
    180 						literal("(shell"),
    181 						literal(`make --version | ruby -n0e 'puts $_[/Make (\d)/,1]'`),
    182 					},
    183 				},
    184 			},
    185 		},
    186 		{
    187 			in: `$(and ${TRUE}, $(X)   )`,
    188 			val: &funcAnd{
    189 				fclosure: fclosure{
    190 					args: []Value{
    191 						literal("(and"),
    192 						&varref{
    193 							varname: literal("TRUE"),
    194 							paren:   '{',
    195 						},
    196 						&varref{
    197 							varname: literal("X"),
    198 							paren:   '(',
    199 						},
    200 					},
    201 				},
    202 			},
    203 		},
    204 		{
    205 			in: `$(call func, \
    206 	foo)`,
    207 			val: &funcCall{
    208 				fclosure: fclosure{
    209 					args: []Value{
    210 						literal("(call"),
    211 						literal("func"),
    212 						literal(" foo"),
    213 					},
    214 				},
    215 			},
    216 		},
    217 		{
    218 			in: `$(call func, \)`,
    219 			val: &funcCall{
    220 				fclosure: fclosure{
    221 					args: []Value{
    222 						literal("(call"),
    223 						literal("func"),
    224 						literal(` \`),
    225 					},
    226 				},
    227 			},
    228 		},
    229 		{
    230 			in: `$(eval ## comment)`,
    231 			val: &funcNop{
    232 				expr: `$(eval ## comment)`,
    233 			},
    234 		},
    235 		{
    236 			in: `$(eval foo = bar)`,
    237 			val: &funcEvalAssign{
    238 				lhs: "foo",
    239 				op:  "=",
    240 				rhs: literal("bar"),
    241 			},
    242 		},
    243 		{
    244 			in: `$(eval foo :=)`,
    245 			val: &funcEvalAssign{
    246 				lhs: "foo",
    247 				op:  ":=",
    248 				rhs: literal(""),
    249 			},
    250 		},
    251 		{
    252 			in: `$(eval foo := $(bar))`,
    253 			val: &funcEvalAssign{
    254 				lhs: "foo",
    255 				op:  ":=",
    256 				rhs: &varref{
    257 					varname: literal("bar"),
    258 					paren:   '(',
    259 				},
    260 			},
    261 		},
    262 		{
    263 			in: `$(eval foo := $$(bar))`,
    264 			val: &funcEvalAssign{
    265 				lhs: "foo",
    266 				op:  ":=",
    267 				rhs: literal("$(bar)"),
    268 			},
    269 		},
    270 		{
    271 			in: `$(strip $1)`,
    272 			val: &funcStrip{
    273 				fclosure: fclosure{
    274 					args: []Value{
    275 						literal("(strip"),
    276 						paramref(1),
    277 					},
    278 				},
    279 			},
    280 		},
    281 		{
    282 			in: `$(strip $(1))`,
    283 			val: &funcStrip{
    284 				fclosure: fclosure{
    285 					args: []Value{
    286 						literal("(strip"),
    287 						paramref(1),
    288 					},
    289 				},
    290 			},
    291 		},
    292 	} {
    293 		val, _, err := parseExpr([]byte(tc.in), nil, parseOp{alloc: true})
    294 		if tc.isErr {
    295 			if err == nil {
    296 				t.Errorf(`parseExpr(%q)=_, _, nil; want error`, tc.in)
    297 			}
    298 			continue
    299 		}
    300 		if err != nil {
    301 			t.Errorf(`parseExpr(%q)=_, _, %v; want nil error`, tc.in, err)
    302 			continue
    303 		}
    304 		if got, want := val, tc.val; !reflect.DeepEqual(got, want) {
    305 			t.Errorf("parseExpr(%[1]q)=%[2]q %#[2]v, _, _;\n want %[3]q %#[3]v, _, _", tc.in, got, want)
    306 		}
    307 	}
    308 }
    309