You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
5.4 KiB
308 lines
5.4 KiB
// Copyright 2015 Google Inc. All rights reserved |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
package kati |
|
|
|
import ( |
|
"reflect" |
|
"testing" |
|
) |
|
|
|
func TestParseExpr(t *testing.T) { |
|
for _, tc := range []struct { |
|
in string |
|
val Value |
|
isErr bool |
|
}{ |
|
{ |
|
in: "foo", |
|
val: literal("foo"), |
|
}, |
|
{ |
|
in: "(foo)", |
|
val: literal("(foo)"), |
|
}, |
|
{ |
|
in: "{foo}", |
|
val: literal("{foo}"), |
|
}, |
|
{ |
|
in: "$$", |
|
val: literal("$"), |
|
}, |
|
{ |
|
in: "foo$$bar", |
|
val: literal("foo$bar"), |
|
}, |
|
{ |
|
in: "$foo", |
|
val: expr{&varref{varname: literal("f")}, literal("oo")}, |
|
}, |
|
{ |
|
in: "$(foo)", |
|
val: &varref{varname: literal("foo"), paren: '('}, |
|
}, |
|
{ |
|
in: "$(foo:.c=.o)", |
|
val: varsubst{ |
|
varname: literal("foo"), |
|
pat: literal(".c"), |
|
subst: literal(".o"), |
|
paren: '(', |
|
}, |
|
}, |
|
{ |
|
in: "$(subst $(space),$(,),$(foo))/bar", |
|
val: expr{ |
|
&funcSubst{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(subst"), |
|
&varref{ |
|
varname: literal("space"), |
|
paren: '(', |
|
}, |
|
&varref{ |
|
varname: literal(","), |
|
paren: '(', |
|
}, |
|
&varref{ |
|
varname: literal("foo"), |
|
paren: '(', |
|
}, |
|
}, |
|
}, |
|
}, |
|
literal("/bar"), |
|
}, |
|
}, |
|
{ |
|
in: "$(subst $(space),$,,$(foo))", |
|
val: &funcSubst{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(subst"), |
|
&varref{ |
|
varname: literal("space"), |
|
paren: '(', |
|
}, |
|
&varref{ |
|
varname: literal(""), |
|
}, |
|
expr{ |
|
literal(","), |
|
&varref{ |
|
varname: literal("foo"), |
|
paren: '(', |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(shell echo '()')`, |
|
val: &funcShell{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(shell"), |
|
literal("echo '()'"), |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `${shell echo '()'}`, |
|
val: &funcShell{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("{shell"), |
|
literal("echo '()'"), |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(shell echo ')')`, |
|
val: expr{ |
|
&funcShell{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(shell"), |
|
literal("echo '"), |
|
}, |
|
}, |
|
}, |
|
literal("')"), |
|
}, |
|
}, |
|
{ |
|
in: `${shell echo ')'}`, |
|
val: &funcShell{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("{shell"), |
|
literal("echo ')'"), |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `${shell echo '}'}`, |
|
val: expr{ |
|
&funcShell{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("{shell"), |
|
literal("echo '"), |
|
}, |
|
}, |
|
}, |
|
literal("'}"), |
|
}, |
|
}, |
|
{ |
|
in: `$(shell make --version | ruby -n0e 'puts $$_[/Make (\d)/,1]')`, |
|
val: &funcShell{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(shell"), |
|
literal(`make --version | ruby -n0e 'puts $_[/Make (\d)/,1]'`), |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(and ${TRUE}, $(X) )`, |
|
val: &funcAnd{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(and"), |
|
&varref{ |
|
varname: literal("TRUE"), |
|
paren: '{', |
|
}, |
|
&varref{ |
|
varname: literal("X"), |
|
paren: '(', |
|
}, |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(call func, \ |
|
foo)`, |
|
val: &funcCall{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(call"), |
|
literal("func"), |
|
literal(" foo"), |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(call func, \)`, |
|
val: &funcCall{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(call"), |
|
literal("func"), |
|
literal(` \`), |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(eval ## comment)`, |
|
val: &funcNop{ |
|
expr: `$(eval ## comment)`, |
|
}, |
|
}, |
|
{ |
|
in: `$(eval foo = bar)`, |
|
val: &funcEvalAssign{ |
|
lhs: "foo", |
|
op: "=", |
|
rhs: literal("bar"), |
|
}, |
|
}, |
|
{ |
|
in: `$(eval foo :=)`, |
|
val: &funcEvalAssign{ |
|
lhs: "foo", |
|
op: ":=", |
|
rhs: literal(""), |
|
}, |
|
}, |
|
{ |
|
in: `$(eval foo := $(bar))`, |
|
val: &funcEvalAssign{ |
|
lhs: "foo", |
|
op: ":=", |
|
rhs: &varref{ |
|
varname: literal("bar"), |
|
paren: '(', |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(eval foo := $$(bar))`, |
|
val: &funcEvalAssign{ |
|
lhs: "foo", |
|
op: ":=", |
|
rhs: literal("$(bar)"), |
|
}, |
|
}, |
|
{ |
|
in: `$(strip $1)`, |
|
val: &funcStrip{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(strip"), |
|
paramref(1), |
|
}, |
|
}, |
|
}, |
|
}, |
|
{ |
|
in: `$(strip $(1))`, |
|
val: &funcStrip{ |
|
fclosure: fclosure{ |
|
args: []Value{ |
|
literal("(strip"), |
|
paramref(1), |
|
}, |
|
}, |
|
}, |
|
}, |
|
} { |
|
val, _, err := parseExpr([]byte(tc.in), nil, parseOp{alloc: true}) |
|
if tc.isErr { |
|
if err == nil { |
|
t.Errorf(`parseExpr(%q)=_, _, nil; want error`, tc.in) |
|
} |
|
continue |
|
} |
|
if err != nil { |
|
t.Errorf(`parseExpr(%q)=_, _, %v; want nil error`, tc.in, err) |
|
continue |
|
} |
|
if got, want := val, tc.val; !reflect.DeepEqual(got, want) { |
|
t.Errorf("parseExpr(%[1]q)=%[2]q %#[2]v, _, _;\n want %[3]q %#[3]v, _, _", tc.in, got, want) |
|
} |
|
} |
|
}
|
|
|