// 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)
}
}
}