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 15package kati 16 17import ( 18 "reflect" 19 "testing" 20) 21 22func 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