github.com/informationsea/shellflow@v0.1.3/flowscript/flowscript_evaluate_test.go (about)

     1  package flowscript
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"testing"
     7  )
     8  
     9  func createTestGlobalEnvironment() Environment {
    10  	ge := NewGlobalEnvironment()
    11  
    12  	ge.Assign("hoge", StringValue{"hoge"})
    13  	ge.Assign("foo", StringValue{"foo"})
    14  	ge.Assign("bar", IntValue{1})
    15  	ge.Assign("v1", StringValue{"1"})
    16  
    17  	var a1 []Value = make([]Value, 3)
    18  	a1[0] = IntValue{10}
    19  	a1[1] = IntValue{11}
    20  	a1[2] = StringValue{"12"}
    21  	ge.Assign("array", ArrayValue{a1})
    22  
    23  	var m1 map[string]Value = make(map[string]Value)
    24  	m1["1"] = IntValue{1}
    25  	m1["2"] = IntValue{2}
    26  	m1["3"] = StringValue{"3!"}
    27  	ge.Assign("map", MapValue{m1})
    28  
    29  	return ge
    30  }
    31  
    32  func TestConstantValueAccess(t *testing.T) {
    33  	env := createTestGlobalEnvironment()
    34  	var x1 Evaluable = ValueEvaluable{IntValue{1}}
    35  	if v, e := x1.Evaluate(env); e != nil || v != (IntValue{1}) {
    36  		t.Fatalf("Invalid value %s or error %s", v, e)
    37  	}
    38  	if len(x1.SubEvaluable()) != 0 {
    39  		t.Fatalf("too many sub-evaluable: %s", x1.SubEvaluable())
    40  	}
    41  
    42  	var x2 Evaluable = ValueEvaluable{StringValue{"hoge"}}
    43  	if v, e := x2.Evaluate(env); e != nil || v != (StringValue{"hoge"}) {
    44  		t.Fatalf("Invalid value %s or error %s", v, e)
    45  	}
    46  
    47  	{
    48  		array := [...]Value{IntValue{1}, IntValue{2}, IntValue{3}}
    49  		var x3 Evaluable = ValueEvaluable{ArrayValue{array[:]}}
    50  		v, e := x3.Evaluate(env)
    51  		if e != nil {
    52  			t.Fatalf("Invalid value %s or error %s", v, e)
    53  		}
    54  
    55  		if rv, ok := v.(ArrayValue); !ok || !reflect.DeepEqual(array[:], rv.value) {
    56  			t.Fatalf("Invalid value %s or error %s", v, e)
    57  		}
    58  	}
    59  
    60  	var badAccess Evaluable = BadEvaluable{}
    61  	if v, e := badAccess.Evaluate(env); e.Error() != "bad access" || v != nil {
    62  		t.Fatalf("Invalid value %s or error %s", v, e)
    63  	}
    64  }
    65  
    66  func TestVariableAccess(t *testing.T) {
    67  
    68  	var ge Environment = createTestGlobalEnvironment()
    69  
    70  	var evaluable Evaluable = &Variable{"hoge"}
    71  	var v Value
    72  	var e error
    73  
    74  	v, e = evaluable.Evaluate(ge)
    75  	if e != nil {
    76  		t.Fatal("Cannot access hoge variable")
    77  	}
    78  	if v != (StringValue{"hoge"}) {
    79  		t.Fatalf("Invalid value %s", v)
    80  	}
    81  	if len(evaluable.SubEvaluable()) != 0 {
    82  		t.Fatalf("too many sub-evaluable: %s", evaluable.SubEvaluable())
    83  	}
    84  
    85  	evaluable = &Variable{"hoge"}
    86  	v, e = evaluable.Evaluate(ge)
    87  	if e != nil {
    88  		t.Fatal("Cannot access hoge variable")
    89  	}
    90  	if v != (StringValue{"hoge"}) {
    91  		t.Fatalf("Invalid value %s", v)
    92  	}
    93  
    94  	evaluable = &Variable{"unknown"}
    95  	v, e = evaluable.Evaluate(ge)
    96  	if e == nil {
    97  		t.Fatal("unknown variable should not exits in global environment #1")
    98  	}
    99  	if v != nil {
   100  		t.Fatal("unknown variable should not exits in global environment #2")
   101  	}
   102  
   103  	ge.Assign("unknown", StringValue{"yes"})
   104  	v, e = evaluable.Evaluate(ge)
   105  	if e != nil {
   106  		t.Fatal("Cannot access hoge variable")
   107  	}
   108  	if v != (StringValue{"yes"}) {
   109  		t.Fatalf("Invalid value %s", v)
   110  	}
   111  }
   112  
   113  func TestArrayAccess(t *testing.T) {
   114  	ge := createTestGlobalEnvironment()
   115  
   116  	originalArray := make([]Value, 3)
   117  	originalArray[0] = IntValue{1}
   118  	originalArray[1] = StringValue{"hoge"}
   119  	originalArray[2] = StringValue{"foo"}
   120  
   121  	// check normal access path
   122  	var arrayAccess1 Evaluable = &ArrayAccess{Array: ValueEvaluable{ArrayValue{originalArray}}, ArrayIndex: ValueEvaluable{IntValue{1}}}
   123  	if v, e := arrayAccess1.Evaluate(ge); v != (StringValue{"hoge"}) || e != nil {
   124  		t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   125  	}
   126  
   127  	if s := arrayAccess1.String(); s != "[1, \"hoge\", \"foo\"][1]" {
   128  		t.Fatalf("Bad string representation: %s", s)
   129  	}
   130  
   131  	subEvaluable := arrayAccess1.SubEvaluable()
   132  	if len(subEvaluable) != 2 || subEvaluable[1] != (ValueEvaluable{IntValue{1}}) {
   133  		t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   134  	}
   135  	subEvaluable1, ok := subEvaluable[0].(ValueEvaluable).value.(ArrayValue)
   136  	if !ok {
   137  		t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   138  	}
   139  	if !reflect.DeepEqual(subEvaluable1.value, originalArray) {
   140  		t.Fatalf("bad sub-evaluable: %s", subEvaluable1.value)
   141  	}
   142  
   143  	ge.Assign("foo", ArrayValue{originalArray})
   144  	ge.Assign("bar", IntValue{0})
   145  	var arrayAccess2 Evaluable = &ArrayAccess{Array: &Variable{"foo"}, ArrayIndex: &Variable{"bar"}}
   146  	if v, e := arrayAccess2.Evaluate(ge); v != (IntValue{1}) || e != nil {
   147  		t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   148  	}
   149  
   150  	if s := arrayAccess2.String(); s != "foo[bar]" {
   151  		t.Fatalf("Bad string representation: %s", s)
   152  	}
   153  
   154  	// check out of index path
   155  	{
   156  		arrayAccess := ArrayAccess{Array: ValueEvaluable{ArrayValue{originalArray}}, ArrayIndex: ValueEvaluable{IntValue{3}}}
   157  		if v, e := arrayAccess.Evaluate(ge); v != (nil) ||
   158  			!strings.HasPrefix(e.Error(), "out of index error") {
   159  
   160  			t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   161  		}
   162  	}
   163  
   164  	{
   165  		arrayAccess := ArrayAccess{Array: ValueEvaluable{ArrayValue{originalArray}}, ArrayIndex: ValueEvaluable{IntValue{-1}}}
   166  		if v, e := arrayAccess.Evaluate(ge); v != (nil) ||
   167  			!strings.HasPrefix(e.Error(), "out of index error") {
   168  
   169  			t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   170  		}
   171  	}
   172  
   173  	// check invalid type path
   174  	{
   175  		arrayAccess := ArrayAccess{Array: ValueEvaluable{StringValue{"hoge"}}, ArrayIndex: ValueEvaluable{IntValue{0}}}
   176  		if v, e := arrayAccess.Evaluate(ge); v != (nil) || e == nil ||
   177  			e.Error() != "\"hoge\" is not array or map" {
   178  			t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   179  		}
   180  	}
   181  
   182  	{
   183  		arrayAccess := ArrayAccess{Array: ValueEvaluable{IntValue{123}}, ArrayIndex: ValueEvaluable{IntValue{0}}}
   184  		if v, e := arrayAccess.Evaluate(ge); v != (nil) || e == nil ||
   185  			e.Error() != "123 is not array or map" {
   186  			t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   187  		}
   188  	}
   189  
   190  	{
   191  		arrayAccess := ArrayAccess{Array: ValueEvaluable{ArrayValue{originalArray}}, ArrayIndex: ValueEvaluable{StringValue{"hoge"}}}
   192  		if v, e := arrayAccess.Evaluate(ge); v != (nil) || e == nil ||
   193  			e.Error() != "\"hoge\" is not int" {
   194  			t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   195  		}
   196  	}
   197  
   198  	// check evaluation fail path
   199  	{
   200  		arrayAccess := ArrayAccess{Array: ValueEvaluable{ArrayValue{originalArray}}, ArrayIndex: BadEvaluable{}}
   201  		if v, e := arrayAccess.Evaluate(ge); v != (nil) || e == nil ||
   202  			e.Error() != "bad access" {
   203  			t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   204  		}
   205  	}
   206  
   207  	{
   208  		arrayAccess := ArrayAccess{Array: BadEvaluable{}, ArrayIndex: ValueEvaluable{IntValue{0}}}
   209  		if v, e := arrayAccess.Evaluate(ge); v != (nil) || e == nil ||
   210  			e.Error() != "bad access" {
   211  
   212  			t.Fatalf("Invalid array access result:%s / error:%s", v, e)
   213  		}
   214  	}
   215  }
   216  
   217  func TestMapAccess(t *testing.T) {
   218  	ge := createTestGlobalEnvironment()
   219  	{
   220  		var mapAccess Evaluable = &ArrayAccess{Array: &Variable{"map"}, ArrayIndex: ValueEvaluable{StringValue{"3"}}}
   221  		if v, e := mapAccess.Evaluate(ge); v != (StringValue{"3!"}) || e != nil {
   222  			t.Fatalf("Invalid map access result:%s / error:%s", v, e)
   223  		}
   224  
   225  		subEvaluable := mapAccess.SubEvaluable()
   226  		if len(subEvaluable) != 2 || subEvaluable[1] != (ValueEvaluable{StringValue{"3"}}) {
   227  			t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   228  		}
   229  		subEvaluable1, ok := subEvaluable[0].(*Variable)
   230  		if !ok || subEvaluable1.Name != "map" {
   231  			t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   232  		}
   233  	}
   234  	{
   235  		var mapAccess Evaluable = &ArrayAccess{Array: &Variable{"map"}, ArrayIndex: &Variable{"v1"}}
   236  		if v, e := mapAccess.Evaluate(ge); v != (IntValue{1}) || e != nil {
   237  			t.Fatalf("Invalid map access result:%s / error:%s", v, e)
   238  		}
   239  	}
   240  
   241  	{
   242  		var mapAccess Evaluable = &ArrayAccess{Array: &Variable{"map"}, ArrayIndex: ValueEvaluable{StringValue{"bad"}}}
   243  		if v, e := mapAccess.Evaluate(ge); v != nil || e.Error() != "bad is not found in map" {
   244  			t.Fatalf("Invalid map access result:%s / error:%s", v, e)
   245  		}
   246  	}
   247  
   248  	// check invalid type path
   249  	{
   250  		var mapAccess Evaluable = &ArrayAccess{Array: &Variable{"map"}, ArrayIndex: ValueEvaluable{BadValue{}}}
   251  		if v, e := mapAccess.Evaluate(ge); v != nil || e.Error() != "bad value is not string" {
   252  			t.Fatalf("Invalid map access result:%s / error:%s", v, e)
   253  		}
   254  	}
   255  
   256  	// check evaluation fail path
   257  	{
   258  		var mapAccess Evaluable = &ArrayAccess{Array: &Variable{"map"}, ArrayIndex: BadEvaluable{}}
   259  		if v, e := mapAccess.Evaluate(ge); v != nil || e.Error() != "bad access" {
   260  			t.Fatalf("Invalid map access result:%s / error:%s", v, e)
   261  		}
   262  	}
   263  }
   264  
   265  func TestPlusExpression(t *testing.T) {
   266  	ge := createTestGlobalEnvironment()
   267  	{
   268  		var plusExpression Evaluable = &PlusExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: ValueEvaluable{IntValue{2}}}
   269  		if v, e := plusExpression.Evaluate(ge); e != nil || v != (IntValue{3}) {
   270  			t.Fatalf("Invalid plus operation value: %s / error: %s", v, e)
   271  		}
   272  		if v := plusExpression.String(); v != "1 + 2" {
   273  			t.Fatalf("bad string representation: %s", v)
   274  		}
   275  		subEvaluable := plusExpression.SubEvaluable()
   276  		if len(subEvaluable) != 2 || subEvaluable[0] != (ValueEvaluable{IntValue{1}}) || subEvaluable[1] != (ValueEvaluable{IntValue{2}}) {
   277  			t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   278  		}
   279  	}
   280  
   281  	{
   282  		var plusExpression Evaluable = &PlusExpression{exp1: ValueEvaluable{StringValue{"hoge"}}, exp2: ValueEvaluable{IntValue{2}}}
   283  		if v, e := plusExpression.Evaluate(ge); e != nil || v != (StringValue{"hoge2"}) {
   284  			t.Fatalf("Invalid plus operation value: %s / error: %s", v, e)
   285  		}
   286  		if v := plusExpression.String(); v != "\"hoge\" + 2" {
   287  			t.Fatalf("bad string representation: %s", v)
   288  		}
   289  	}
   290  
   291  	{
   292  		var plusExpression Evaluable = &PlusExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: ValueEvaluable{StringValue{"foo"}}}
   293  		if v, e := plusExpression.Evaluate(ge); e != nil || v != (StringValue{"1foo"}) {
   294  			t.Fatalf("Invalid plus operation value: %s / error: %s", v, e)
   295  		}
   296  		if v := plusExpression.String(); v != "1 + \"foo\"" {
   297  			t.Fatalf("bad string representation: %s", v)
   298  		}
   299  	}
   300  
   301  	{
   302  		var plusExpression Evaluable = &PlusExpression{exp1: ValueEvaluable{StringValue{"foo"}}, exp2: ValueEvaluable{StringValue{"bar"}}}
   303  		if v, e := plusExpression.Evaluate(ge); e != nil || v != (StringValue{"foobar"}) {
   304  			t.Fatalf("Invalid plus operation value: %s / error: %s", v, e)
   305  		}
   306  	}
   307  
   308  	{
   309  		var numericOperation Evaluable = &PlusExpression{exp1: BadEvaluable{}, exp2: ValueEvaluable{IntValue{2}}}
   310  		if v, e := numericOperation.Evaluate(ge); e == nil || v != (nil) || e.Error() != "bad access" {
   311  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   312  		}
   313  	}
   314  
   315  	{
   316  		var numericOperation Evaluable = &PlusExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: BadEvaluable{}}
   317  		if v, e := numericOperation.Evaluate(ge); e == nil || v != (nil) || e.Error() != "bad access" {
   318  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   319  		}
   320  	}
   321  
   322  	{
   323  		var numericOperation Evaluable = &PlusExpression{exp1: ValueEvaluable{BadValue{}}, exp2: ValueEvaluable{IntValue{2}}}
   324  		if v, e := numericOperation.Evaluate(ge); e == nil || v != (nil) || !strings.HasPrefix(e.Error(), "cannot combine") {
   325  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   326  		}
   327  	}
   328  
   329  	{
   330  		var numericOperation Evaluable = &PlusExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: ValueEvaluable{BadValue{}}}
   331  		if v, e := numericOperation.Evaluate(ge); e == nil || v != (nil) || !strings.HasPrefix(e.Error(), "cannot combine") {
   332  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   333  		}
   334  	}
   335  
   336  }
   337  
   338  func TestNumericOperationExpression(t *testing.T) {
   339  	ge := createTestGlobalEnvironment()
   340  	{
   341  		var numericOperation = &NumericOperationExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: ValueEvaluable{IntValue{2}}, operator: "+"}
   342  		if v, e := numericOperation.Evaluate(ge); e != nil || v != (IntValue{3}) {
   343  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   344  		}
   345  		if v := numericOperation.String(); v != "1 + 2" {
   346  			t.Fatalf("bad string representation: %s", v)
   347  		}
   348  		subEvaluable := numericOperation.SubEvaluable()
   349  		if len(subEvaluable) != 2 || subEvaluable[0] != (ValueEvaluable{IntValue{1}}) || subEvaluable[1] != (ValueEvaluable{IntValue{2}}) {
   350  			t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   351  		}
   352  	}
   353  
   354  	{
   355  		var numericOperation = &NumericOperationExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: ValueEvaluable{IntValue{2}}, operator: "-"}
   356  		if v, e := numericOperation.Evaluate(ge); e != nil || v != (IntValue{-1}) {
   357  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   358  		}
   359  		if v := numericOperation.String(); v != "1 - 2" {
   360  			t.Fatalf("bad string representation: %s", v)
   361  		}
   362  	}
   363  
   364  	{
   365  		var numericOperation = &NumericOperationExpression{exp1: ValueEvaluable{IntValue{2}}, exp2: ValueEvaluable{IntValue{2}}, operator: "*"}
   366  		if v, e := numericOperation.Evaluate(ge); e != nil || v != (IntValue{4}) {
   367  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   368  		}
   369  		if v := numericOperation.String(); v != "2 * 2" {
   370  			t.Fatalf("bad string representation: %s", v)
   371  		}
   372  	}
   373  
   374  	{
   375  		var numericOperation = &NumericOperationExpression{exp1: ValueEvaluable{IntValue{4}}, exp2: ValueEvaluable{IntValue{2}}, operator: "/"}
   376  		if v, e := numericOperation.Evaluate(ge); e != nil || v != (IntValue{2}) {
   377  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   378  		}
   379  		if v := numericOperation.String(); v != "4 / 2" {
   380  			t.Fatalf("bad string representation: %s", v)
   381  		}
   382  	}
   383  
   384  	{
   385  		var numericOperation = &NumericOperationExpression{exp1: BadEvaluable{}, exp2: ValueEvaluable{IntValue{2}}, operator: "/"}
   386  		if v, e := numericOperation.Evaluate(ge); e == nil || v != nil || e.Error() != "bad access" {
   387  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   388  		}
   389  	}
   390  
   391  	{
   392  		var numericOperation = &NumericOperationExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: BadEvaluable{}, operator: "/"}
   393  		if v, e := numericOperation.Evaluate(ge); e == nil || v != (nil) || e.Error() != "bad access" {
   394  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   395  		}
   396  	}
   397  
   398  	{
   399  		var numericOperation = &NumericOperationExpression{exp1: ValueEvaluable{StringValue{"foo"}}, exp2: ValueEvaluable{IntValue{2}}, operator: "/"}
   400  		if v, e := numericOperation.Evaluate(ge); e == nil || v != (nil) || !strings.HasPrefix(e.Error(), "cannot calculate") {
   401  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   402  		}
   403  	}
   404  
   405  	{
   406  		var numericOperation Evaluable = &NumericOperationExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: ValueEvaluable{StringValue{"foo"}}, operator: "/"}
   407  		if v, e := numericOperation.Evaluate(ge); e == nil || v != (nil) || !strings.HasPrefix(e.Error(), "cannot calculate") {
   408  			t.Fatalf("Invalid numeric operation value: %s / error: %s", v, e)
   409  		}
   410  	}
   411  }
   412  
   413  func TestJoinedExpression(t *testing.T) {
   414  	ge := createTestGlobalEnvironment()
   415  
   416  	{
   417  		var joinedExpression Evaluable = &JoinedExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: ValueEvaluable{IntValue{2}}}
   418  		if v, e := joinedExpression.Evaluate(ge); e != nil || v != (IntValue{2}) {
   419  			t.Fatalf("Invalid joined expression value: %s / error: %s", v, e)
   420  		}
   421  		if s := joinedExpression.String(); s != "1; 2" {
   422  			t.Fatalf("bad string representation: %s", s)
   423  		}
   424  		subEvaluable := joinedExpression.SubEvaluable()
   425  		if len(subEvaluable) != 2 || subEvaluable[0] != (ValueEvaluable{IntValue{1}}) || subEvaluable[1] != (ValueEvaluable{IntValue{2}}) {
   426  			t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   427  		}
   428  	}
   429  
   430  	{
   431  		var joinedExpression Evaluable = &JoinedExpression{exp1: BadEvaluable{}, exp2: ValueEvaluable{IntValue{2}}}
   432  		if v, e := joinedExpression.Evaluate(ge); e == nil || v != (nil) || e.Error() != "bad access" {
   433  			t.Fatalf("Invalid joined expression value: %s / error: %s", v, e)
   434  		}
   435  		if s := joinedExpression.String(); s != "bad access; 2" {
   436  			t.Fatalf("bad string representation: %s", s)
   437  		}
   438  	}
   439  
   440  	{
   441  		var joinedExpression Evaluable = &JoinedExpression{exp1: ValueEvaluable{IntValue{1}}, exp2: BadEvaluable{}}
   442  		if v, e := joinedExpression.Evaluate(ge); e == nil || v != (nil) || e.Error() != "bad access" {
   443  			t.Fatalf("Invalid joined expression value: %s / error: %s", v, e)
   444  		}
   445  	}
   446  }
   447  
   448  func TestAssignExpression(t *testing.T) {
   449  	ge := createTestGlobalEnvironment()
   450  
   451  	{
   452  		var assignExpression Evaluable = &AssignExpression{variable: &Variable{"x"}, exp: ValueEvaluable{IntValue{2}}}
   453  		v, e := assignExpression.Evaluate(ge)
   454  		av, ae := ge.Value("x")
   455  		if e != nil || ae != nil || v != (IntValue{2}) || av != (IntValue{2}) {
   456  			t.Fatalf("Invalid joined expression value: %s / error: %s / assigned: %s / env error: %s", v, e, av, ae)
   457  		}
   458  		if s := assignExpression.String(); s != "x = 2" {
   459  			t.Fatalf("bad string representation: %s", s)
   460  		}
   461  		subEvaluable := assignExpression.SubEvaluable()
   462  		if len(subEvaluable) != 2 || subEvaluable[0].(*Variable).Name != "x" || subEvaluable[1] != (ValueEvaluable{IntValue{2}}) {
   463  			t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   464  		}
   465  	}
   466  
   467  	{
   468  		var assignExpression Evaluable = &AssignExpression{variable: &Variable{"y"}, exp: ValueEvaluable{StringValue{"hoge"}}}
   469  		v, e := assignExpression.Evaluate(ge)
   470  		av, ae := ge.Value("y")
   471  		if e != nil || ae != nil || v != (StringValue{"hoge"}) || av != (StringValue{"hoge"}) {
   472  			t.Fatalf("Invalid joined expression value: %s / error: %s / assigned: %s / env error: %s", v, e, av, ae)
   473  		}
   474  		if s := assignExpression.String(); s != "y = \"hoge\"" {
   475  			t.Fatalf("bad string representation: %s", s)
   476  		}
   477  	}
   478  
   479  	{
   480  		var assignExpression Evaluable = &AssignExpression{variable: &Variable{"hoge"}, exp: BadEvaluable{}}
   481  		v, e := assignExpression.Evaluate(ge)
   482  		av, ae := ge.Value("hoge") // check overwriting
   483  		if e == nil || e.Error() != "bad access" || ae != nil || v != (nil) || av != (StringValue{"hoge"}) {
   484  			t.Fatalf("Invalid joined expression value: %s / error: %s / assigned: %s / env error: %s", v, e, av, ae)
   485  		}
   486  
   487  	}
   488  
   489  	{
   490  		var assignExpression Evaluable = &AssignExpression{variable: ValueEvaluable{IntValue{1}}, exp: ValueEvaluable{IntValue{2}}}
   491  		v, e := assignExpression.Evaluate(ge)
   492  		if e == nil || e.Error() != "1 is not variable" || v != (nil) {
   493  			t.Fatalf("Invalid joined expression value: %s / error: %s", v, e)
   494  		}
   495  	}
   496  }
   497  
   498  func TestFunctionCall(t *testing.T) {
   499  	ge := createTestGlobalEnvironment()
   500  
   501  	{
   502  		args := [...]Evaluable{ValueEvaluable{StringValue{"hoge/foo"}}}
   503  		dirname := BuiltinFunctions["dirname"]
   504  		var function Evaluable = &FunctionCall{function: ValueEvaluable{FunctionValue{dirname}}, args: args[:]}
   505  
   506  		if subEvaluable := function.SubEvaluable(); len(subEvaluable) != 2 || subEvaluable[0].(ValueEvaluable).value != (StringValue{"hoge/foo"}) || subEvaluable[1] != (ValueEvaluable{FunctionValue{dirname}}) {
   507  			t.Fatalf("bad sub-evaluable: %s", subEvaluable)
   508  		}
   509  
   510  		if r, e := function.Evaluate(ge); e != nil || r != (StringValue{"hoge"}) {
   511  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   512  		}
   513  		if r := function.String(); r != "dirname(\"hoge/foo\")" {
   514  			t.Fatalf("Invalid result: %s", r)
   515  		}
   516  	}
   517  
   518  	{
   519  		args := [...]Evaluable{ValueEvaluable{StringValue{"hoge/foo.c"}}, ValueEvaluable{StringValue{".c"}}}
   520  		basename := BuiltinFunctions["basename"]
   521  		var function Evaluable = &FunctionCall{function: ValueEvaluable{FunctionValue{basename}}, args: args[:]}
   522  
   523  		if subEvaluable := function.SubEvaluable(); len(subEvaluable) != 3 || subEvaluable[0].(ValueEvaluable).value != (StringValue{"hoge/foo.c"}) || subEvaluable[1].(ValueEvaluable).value != (StringValue{".c"}) || subEvaluable[2] != (ValueEvaluable{FunctionValue{basename}}) {
   524  			t.Fatalf("bad sub-evaluable: %s / condition %t %t %t", subEvaluable, subEvaluable[0].(ValueEvaluable).value != (StringValue{"hoge/foo.c"}), subEvaluable[1].(ValueEvaluable).value != (StringValue{".c"}), subEvaluable[2] != (ValueEvaluable{FunctionValue{basename}}))
   525  		}
   526  		if r, e := function.Evaluate(ge); e != nil || r != (StringValue{"foo"}) {
   527  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   528  		}
   529  		if r := function.String(); r != "basename(\"hoge/foo.c\", \".c\")" {
   530  			t.Fatalf("Invalid result: %s", r)
   531  		}
   532  	}
   533  
   534  	{
   535  		args := [...]Evaluable{BadEvaluable{}}
   536  		dirname := BuiltinFunctions["dirname"]
   537  		var function Evaluable = &FunctionCall{function: ValueEvaluable{FunctionValue{dirname}}, args: args[:]}
   538  		if r, e := function.Evaluate(ge); e == nil || e.Error() != "bad access" || r != (nil) {
   539  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   540  		}
   541  	}
   542  
   543  	{
   544  		args := [...]Evaluable{ValueEvaluable{IntValue{1}}}
   545  		var function Evaluable = &FunctionCall{function: BadEvaluable{}, args: args[:]}
   546  		if r, e := function.Evaluate(ge); e == nil || e.Error() != "bad access" || r != (nil) {
   547  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   548  		}
   549  	}
   550  
   551  	{
   552  		args := [...]Evaluable{ValueEvaluable{IntValue{1}}}
   553  		var function Evaluable = &FunctionCall{function: ValueEvaluable{IntValue{1}}, args: args[:]}
   554  		if r, e := function.Evaluate(ge); e == nil || e.Error() != "1 is not function" || r != (nil) {
   555  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   556  		}
   557  	}
   558  }
   559  
   560  func TestArrayExpression(t *testing.T) {
   561  	ge := createTestGlobalEnvironment()
   562  	{
   563  		values := [...]Evaluable{ValueEvaluable{IntValue{1}}, ValueEvaluable{IntValue{2}}, ValueEvaluable{IntValue{3}}}
   564  		expected := [...]Value{IntValue{1}, IntValue{2}, IntValue{3}}
   565  		var arrayExpression Evaluable = &ArrayExpression{values[:]}
   566  		r, e := arrayExpression.Evaluate(ge)
   567  		if e != nil {
   568  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   569  		}
   570  		array, ok := r.(ArrayValue)
   571  		if !ok {
   572  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   573  		}
   574  
   575  		if !reflect.DeepEqual(array.value, expected[:]) {
   576  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   577  		}
   578  
   579  		if s := arrayExpression.String(); s != "[1, 2, 3]" {
   580  			t.Fatalf("Invalid string result: %s", s)
   581  		}
   582  
   583  		if !reflect.DeepEqual(arrayExpression.SubEvaluable(), values[:]) {
   584  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   585  		}
   586  	}
   587  
   588  	{
   589  		values := [...]Evaluable{ValueEvaluable{IntValue{1}}, BadEvaluable{}, ValueEvaluable{IntValue{3}}}
   590  		var arrayExpression Evaluable = &ArrayExpression{values[:]}
   591  		if r, e := arrayExpression.Evaluate(ge); e == nil || r != (nil) || e.Error() != "bad access" {
   592  			t.Fatalf("Invalid result: %s / error: %s", r, e)
   593  		}
   594  	}
   595  }
   596  
   597  func TestSearchDependentVariables(t *testing.T) {
   598  	tokenizer := createInitializedTokenizer("a = b + c + d; k = x / y + basename(\"foo/bar\", z) + b; l = m")
   599  	evaluable, err := ParseAsExp(tokenizer)
   600  	if err != nil {
   601  		t.Fatalf("Failed to parse: %s", err)
   602  	}
   603  	dependentVariables := SearchDependentVariables(evaluable).Array()
   604  
   605  	expected := []string{"b", "basename", "c", "d", "m", "x", "y", "z"}
   606  	if !reflect.DeepEqual(expected, dependentVariables) {
   607  		t.Fatalf("bad dependent variables: %s", dependentVariables)
   608  	}
   609  }
   610  
   611  func TestSearchCreatedVariables(t *testing.T) {
   612  	tokenizer := createInitializedTokenizer("a = b + c + d; k = x / y + basename(\"foo/bar\", z) + b; l = m")
   613  	evaluable, err := ParseAsExp(tokenizer)
   614  	if err != nil {
   615  		t.Fatalf("Failed to parse: %s", err)
   616  	}
   617  	dependentVariables := SearchCreatedVariables(evaluable).Array()
   618  
   619  	expected := []string{"a", "k", "l"}
   620  	if !reflect.DeepEqual(expected, dependentVariables) {
   621  		t.Fatalf("bad created variables: %s", dependentVariables)
   622  	}
   623  }