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

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/informationsea/shellflow/flowscript"
    10  )
    11  
    12  func TestSingleFlowScriptTask(t *testing.T) {
    13  	var task FlowTask
    14  	var err error
    15  
    16  	{
    17  		ge := flowscript.NewGlobalEnvironment()
    18  		builder, err := NewShellTaskBuilder()
    19  		if err != nil {
    20  			t.Fatalf("error: %s", err.Error())
    21  		}
    22  
    23  		task, err = NewSingleFlowScriptTask(10, "#% a = 1; b = 2; c = a")
    24  		if err != nil {
    25  			t.Fatalf("Failed to parse: %s", err)
    26  		}
    27  
    28  		if task.Line() != 10 {
    29  			t.Fatalf("Bad line number: %d", task.Line())
    30  		}
    31  
    32  		err = task.Subscribe(ge, builder)
    33  		if err != nil {
    34  			t.Fatalf("Cannot submit task: %s", err)
    35  		}
    36  
    37  		if v, err := ge.Value("a"); err != nil || v.(flowscript.IntValue).Value() != 1 {
    38  			t.Fatalf("Cannot confirm task result: %s", err)
    39  		}
    40  
    41  		if v, err := ge.Value("b"); err != nil || v.(flowscript.IntValue).Value() != 2 {
    42  			t.Fatalf("Cannot confirm task result: %s", err)
    43  		}
    44  
    45  		if v, err := ge.Value("c"); err != nil || v.(flowscript.IntValue).Value() != 1 {
    46  			t.Fatalf("Cannot confirm task result: %s", err)
    47  		}
    48  
    49  		dependentVariables := task.DependentVariables()
    50  		if !reflect.DeepEqual(dependentVariables.Array(), []string{"a"}) {
    51  			t.Fatalf("Bad dependent variables: %s", dependentVariables.Array())
    52  		}
    53  
    54  		createdVariables := task.CreatedVariables()
    55  		if !reflect.DeepEqual(createdVariables.Array(), []string{"a", "b", "c"}) {
    56  			t.Fatalf("Bad created variables: %s", createdVariables.Array())
    57  		}
    58  	}
    59  
    60  	{
    61  		task, err = NewSingleFlowScriptTask(10, "#% a = !; b = 2; c = a")
    62  		if err == nil || !strings.HasPrefix(err.Error(), "parse error") {
    63  			t.Fatalf("bad parse result: %s", err)
    64  		}
    65  	}
    66  
    67  	{
    68  		task, err = NewSingleFlowScriptTask(10, "# a = !; b = 2; c = a")
    69  		if err == nil || err.Error() != "flowscript line should be started with \"#%\"" {
    70  			t.Fatalf("bad parse result: %s", err)
    71  		}
    72  	}
    73  }
    74  
    75  func TestSingleShellTask(t *testing.T) {
    76  	var task FlowTask
    77  	var err error
    78  
    79  	{
    80  		ge := flowscript.NewGlobalEnvironment()
    81  		_, err = flowscript.EvaluateScript("b = 100; hoge=\"foo\"", ge)
    82  		if err != nil {
    83  			t.Fatalf("Failed to parse: %s", err)
    84  		}
    85  
    86  		task, err = NewSingleShellTask(20, "echo {{a = 1}} {{b}} {{hoge}}")
    87  		if err != nil {
    88  			t.Fatalf("Failed to parse: %s", err)
    89  		}
    90  
    91  		if task.Line() != 20 {
    92  			t.Fatalf("Bad line number: %d", task.Line())
    93  		}
    94  
    95  		expected := [][]int{{5, 14}, {15, 20}, {21, 29}}
    96  		positions := task.(*SingleShellTask).embeddedPositions
    97  		if !reflect.DeepEqual(expected, positions) {
    98  			t.Fatalf("bad positions: %d (%d)", len(positions), positions)
    99  		}
   100  
   101  		runScript, err := task.(*SingleShellTask).EvaluatedShell(ge)
   102  		if err != nil || runScript != "echo 1 100 foo" {
   103  			t.Fatalf("bad result: %s / error: %s", runScript, err)
   104  		}
   105  
   106  		dependentVariables := task.DependentVariables()
   107  		if !reflect.DeepEqual(dependentVariables.Array(), []string{"b", "hoge"}) {
   108  			t.Fatalf("Bad dependent variables: %s", dependentVariables.Array())
   109  		}
   110  
   111  		createdVariables := task.CreatedVariables()
   112  		if !reflect.DeepEqual(createdVariables.Array(), []string{"a"}) {
   113  			t.Fatalf("Bad created variables: %s", createdVariables.Array())
   114  		}
   115  	}
   116  }
   117  
   118  func TestParseShellflow(t *testing.T) {
   119  	testScript := `#!/usr/bin/shellflow
   120  #% x = 1
   121  echo hello, world
   122  #% y = 2
   123  
   124  # comment
   125  
   126  echo {{x}} {{y}} {{z = 3}}
   127  foo {{z}} {{x}}
   128  `
   129  	reader := strings.NewReader(testScript)
   130  	env := NewEnvironment()
   131  	param := make(map[string]interface{})
   132  	builder, err := ParseShellflow(reader, env, param)
   133  	if err != nil {
   134  		t.Fatalf("Error: %s", err.Error())
   135  	}
   136  	if l := len(builder.Tasks); l != 3 {
   137  		t.Fatalf("Invalid number of tasks: %d", l)
   138  	}
   139  
   140  	if x := builder.Tasks[0]; !reflect.DeepEqual(x, &ShellTask{
   141  		LineNum:              3,
   142  		ID:                   1,
   143  		ShellScript:          "echo hello, world",
   144  		DependentFiles:       flowscript.NewStringSet(),
   145  		CreatingFiles:        flowscript.NewStringSet(),
   146  		DependentTaskID:      []int{},
   147  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   148  	}) {
   149  		t.Fatalf("Invalid task:%s", x)
   150  	}
   151  
   152  	if x := builder.Tasks[1]; !reflect.DeepEqual(x, &ShellTask{
   153  		LineNum:              8,
   154  		ID:                   2,
   155  		ShellScript:          "echo 1 2 3",
   156  		DependentFiles:       flowscript.NewStringSetWithValues(),
   157  		CreatingFiles:        flowscript.NewStringSetWithValues(),
   158  		DependentTaskID:      []int{},
   159  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   160  	}) {
   161  		t.Fatalf("Invalid task:%s", x)
   162  	}
   163  
   164  	if x := builder.Tasks[2]; !reflect.DeepEqual(x, &ShellTask{
   165  		LineNum:              9,
   166  		ID:                   3,
   167  		ShellScript:          "foo 3 1",
   168  		DependentFiles:       flowscript.NewStringSet(),
   169  		CreatingFiles:        flowscript.NewStringSet(),
   170  		DependentTaskID:      []int{},
   171  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   172  	}) {
   173  		t.Fatalf("Invalid task:%s", x)
   174  	}
   175  }
   176  
   177  func TestParseShellflowBlock(t *testing.T) {
   178  	testScript := `#!/usr/bin/shellflow
   179  #% x = 1
   180  echo {{x}}
   181  
   182  for y in a b c; do
   183      test {{y}} {{x}}
   184      hoge {{"foo" + y}}
   185  done
   186  
   187  echo {{y}}
   188  
   189  `
   190  	reader := strings.NewReader(testScript)
   191  	env := NewEnvironment()
   192  	block, content, err := ParseShellflowBlock(reader, env)
   193  	if err != nil {
   194  		t.Fatalf("Error: %s", err.Error())
   195  	}
   196  	if content != testScript {
   197  		t.Fatalf("Invalid content: %s", content)
   198  	}
   199  
   200  	parsedAssign, err := flowscript.ParseScript(" x = 1")
   201  	if err != nil {
   202  		t.Fatalf("Failed to parse: %s", err.Error())
   203  	}
   204  
   205  	parsedEcho, err := NewSingleShellTask(3, "echo {{x}}")
   206  	if err != nil {
   207  		t.Fatalf("Failed to parse: %s", err.Error())
   208  	}
   209  
   210  	parsedTest, err := NewSingleShellTask(6, "test {{y}} {{x}}")
   211  	if err != nil {
   212  		t.Fatalf("Failed to parse: %s", err.Error())
   213  	}
   214  
   215  	parsedHoge, err := NewSingleShellTask(7, "hoge {{\"foo\" + y}}")
   216  	if err != nil {
   217  		t.Fatalf("Failed to parse: %s", err.Error())
   218  	}
   219  
   220  	parsedEcho2, err := NewSingleShellTask(10, "echo {{y}}")
   221  	if err != nil {
   222  		t.Fatalf("Failed to parse: %s", err.Error())
   223  	}
   224  
   225  	expected := &SimpleTaskBlock{
   226  		LineNum: 1,
   227  		SubTask: []FlowTask{
   228  			&SingleScriptFlowTask{
   229  				LineNum:   2,
   230  				Script:    " x = 1",
   231  				evaluable: parsedAssign,
   232  			},
   233  			parsedEcho,
   234  			&ForFlowTask{
   235  				LineNum:      5,
   236  				VariableName: "y",
   237  				Items:        []ForItem{StringForItem("a"), StringForItem("b"), StringForItem("c")},
   238  				SubTask:      []FlowTask{parsedTest, parsedHoge},
   239  			},
   240  			parsedEcho2,
   241  		},
   242  	}
   243  
   244  	if !reflect.DeepEqual(block, expected) {
   245  		d, e := json.MarshalIndent(block, "", "  ")
   246  		if e != nil {
   247  			t.Fatalf("bad block and no json: %s", e.Error())
   248  		}
   249  		t.Fatalf("Bad block: %s", d)
   250  	}
   251  
   252  	builder, err := NewShellTaskBuilder()
   253  	if err != nil {
   254  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   255  	}
   256  
   257  	err = block.Subscribe(env.flowEnvironment, builder)
   258  	if err != nil {
   259  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   260  	}
   261  
   262  	if len(builder.Tasks) != 8 {
   263  		t.Fatalf("Invalid number of tasks: %d", len(builder.Tasks))
   264  	}
   265  
   266  	if x := builder.Tasks[0]; !reflect.DeepEqual(x, &ShellTask{
   267  		LineNum:              3,
   268  		ID:                   1,
   269  		ShellScript:          "echo 1",
   270  		DependentFiles:       flowscript.NewStringSet(),
   271  		CreatingFiles:        flowscript.NewStringSet(),
   272  		DependentTaskID:      []int{},
   273  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   274  	}) {
   275  		t.Fatalf("Invalid task:%s", x)
   276  	}
   277  
   278  	if x := builder.Tasks[1]; !reflect.DeepEqual(x, &ShellTask{
   279  		LineNum:              6,
   280  		ID:                   2,
   281  		ShellScript:          "test a 1",
   282  		DependentFiles:       flowscript.NewStringSetWithValues(),
   283  		CreatingFiles:        flowscript.NewStringSetWithValues(),
   284  		DependentTaskID:      []int{},
   285  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   286  	}) {
   287  		t.Fatalf("Invalid task:%s", x)
   288  	}
   289  
   290  	if x := builder.Tasks[2]; !reflect.DeepEqual(x, &ShellTask{
   291  		LineNum:              7,
   292  		ID:                   3,
   293  		ShellScript:          "hoge fooa",
   294  		DependentFiles:       flowscript.NewStringSetWithValues(),
   295  		CreatingFiles:        flowscript.NewStringSetWithValues(),
   296  		DependentTaskID:      []int{},
   297  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   298  	}) {
   299  		t.Fatalf("Invalid task:%s", x)
   300  	}
   301  
   302  	if x := builder.Tasks[3]; !reflect.DeepEqual(x, &ShellTask{
   303  		LineNum:              6,
   304  		ID:                   4,
   305  		ShellScript:          "test b 1",
   306  		DependentFiles:       flowscript.NewStringSetWithValues(),
   307  		CreatingFiles:        flowscript.NewStringSetWithValues(),
   308  		DependentTaskID:      []int{},
   309  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   310  	}) {
   311  		t.Fatalf("Invalid task:%s", x)
   312  	}
   313  
   314  	if x := builder.Tasks[4]; !reflect.DeepEqual(x, &ShellTask{
   315  		LineNum:              7,
   316  		ID:                   5,
   317  		ShellScript:          "hoge foob",
   318  		DependentFiles:       flowscript.NewStringSetWithValues(),
   319  		CreatingFiles:        flowscript.NewStringSetWithValues(),
   320  		DependentTaskID:      []int{},
   321  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   322  	}) {
   323  		t.Fatalf("Invalid task:%s", x)
   324  	}
   325  
   326  	if x := builder.Tasks[5]; !reflect.DeepEqual(x, &ShellTask{
   327  		LineNum:              6,
   328  		ID:                   6,
   329  		ShellScript:          "test c 1",
   330  		DependentFiles:       flowscript.NewStringSetWithValues(),
   331  		CreatingFiles:        flowscript.NewStringSetWithValues(),
   332  		DependentTaskID:      []int{},
   333  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   334  	}) {
   335  		t.Fatalf("Invalid task:%s", x)
   336  	}
   337  
   338  	if x := builder.Tasks[6]; !reflect.DeepEqual(x, &ShellTask{
   339  		LineNum:              7,
   340  		ID:                   7,
   341  		ShellScript:          "hoge fooc",
   342  		DependentFiles:       flowscript.NewStringSetWithValues(),
   343  		CreatingFiles:        flowscript.NewStringSetWithValues(),
   344  		DependentTaskID:      []int{},
   345  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   346  	}) {
   347  		t.Fatalf("Invalid task:%s", x)
   348  	}
   349  
   350  	if x := builder.Tasks[7]; !reflect.DeepEqual(x, &ShellTask{
   351  		LineNum:              10,
   352  		ID:                   8,
   353  		ShellScript:          "echo c",
   354  		DependentFiles:       flowscript.NewStringSet(),
   355  		CreatingFiles:        flowscript.NewStringSet(),
   356  		DependentTaskID:      []int{},
   357  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   358  	}) {
   359  		t.Fatalf("Invalid task:%s", x)
   360  	}
   361  }
   362  
   363  func TestParseShellflowBlock2(t *testing.T) {
   364  	testScript := `#!/usr/bin/shellflow
   365  for y in examples/*.c; do
   366      test {{y}}
   367  done
   368  `
   369  	reader := strings.NewReader(testScript)
   370  	env := NewEnvironment()
   371  	block, content, err := ParseShellflowBlock(reader, env)
   372  	if err != nil {
   373  		t.Fatalf("Error: %s", err.Error())
   374  	}
   375  	if content != testScript {
   376  		t.Fatalf("Invalid content: %s", content)
   377  	}
   378  
   379  	parsedTest, err := NewSingleShellTask(3, "test {{y}}")
   380  	if err != nil {
   381  		t.Fatalf("Failed to parse: %s", err.Error())
   382  	}
   383  
   384  	expected := &SimpleTaskBlock{
   385  		LineNum: 1,
   386  		SubTask: []FlowTask{
   387  			&ForFlowTask{
   388  				LineNum:      2,
   389  				VariableName: "y",
   390  				Items:        []ForItem{StringForItem("examples/hello.c"), StringForItem("examples/helloprint.c")},
   391  				SubTask:      []FlowTask{parsedTest},
   392  			},
   393  		},
   394  	}
   395  
   396  	if !reflect.DeepEqual(block, expected) {
   397  		d, e := json.MarshalIndent(block, "", "  ")
   398  		if e != nil {
   399  			t.Fatalf("bad block and no json: %s", e.Error())
   400  		}
   401  		t.Fatalf("Bad block: %s", d)
   402  	}
   403  }
   404  
   405  func TestParseShellflowBlock3(t *testing.T) {
   406  	testScript := `#!/usr/bin/shellflow
   407  #% a = ["examples/hello.c", "examples/helloprint.c", [1, "value", 3]]
   408  for y in {{a}}; do
   409      test (({{y}}))
   410  done
   411  `
   412  	reader := strings.NewReader(testScript)
   413  	env := NewEnvironment()
   414  	block, content, err := ParseShellflowBlock(reader, env)
   415  	if err != nil {
   416  		t.Fatalf("Error: %s", err.Error())
   417  	}
   418  	if content != testScript {
   419  		t.Fatalf("Invalid content: %s", content)
   420  	}
   421  
   422  	assign, err := NewSingleFlowScriptTask(2, "#% a = [\"examples/hello.c\", \"examples/helloprint.c\", [1, \"value\", 3]]")
   423  	if err != nil {
   424  		t.Fatalf("Failed to parse: %s", err.Error())
   425  	}
   426  
   427  	parsedTest, err := NewSingleShellTask(4, "test (({{y}}))")
   428  	if err != nil {
   429  		t.Fatalf("Failed to parse: %s", err.Error())
   430  	}
   431  
   432  	parsedVal, err := flowscript.ParseScript("a")
   433  	if err != nil {
   434  		t.Fatalf("Failed to parse: %s", err.Error())
   435  	}
   436  
   437  	expected := &SimpleTaskBlock{
   438  		LineNum: 1,
   439  		SubTask: []FlowTask{
   440  			assign,
   441  			&ForFlowTask{
   442  				LineNum:      3,
   443  				VariableName: "y",
   444  				Items:        []ForItem{EvaluableForItem{parsedVal}},
   445  				SubTask:      []FlowTask{parsedTest},
   446  			},
   447  		},
   448  	}
   449  
   450  	if !reflect.DeepEqual(block, expected) {
   451  		d, e := json.MarshalIndent(block, "", "  ")
   452  		if e != nil {
   453  			t.Fatalf("bad block and no json: %s", e.Error())
   454  		}
   455  
   456  		d2, e := json.MarshalIndent(expected, "", "  ")
   457  		if e != nil {
   458  			t.Fatalf("bad block and no json: %s", e.Error())
   459  		}
   460  		t.Fatalf("Bad block: %s / %s", d, d2)
   461  	}
   462  
   463  	builder, err := NewShellTaskBuilder()
   464  	if err != nil {
   465  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   466  	}
   467  
   468  	err = block.Subscribe(env.flowEnvironment, builder)
   469  	if err != nil {
   470  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   471  	}
   472  
   473  	if len(builder.Tasks) != 3 {
   474  		t.Fatalf("Invalid number of tasks: %d", len(builder.Tasks))
   475  	}
   476  
   477  	if x := builder.Tasks[0]; !reflect.DeepEqual(x, &ShellTask{
   478  		LineNum:              4,
   479  		ID:                   1,
   480  		ShellScript:          "test examples/hello.c",
   481  		DependentFiles:       flowscript.NewStringSetWithValues("examples/hello.c"),
   482  		CreatingFiles:        flowscript.NewStringSet(),
   483  		DependentTaskID:      []int{},
   484  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   485  	}) {
   486  		t.Fatalf("Invalid task:%s", x)
   487  	}
   488  
   489  	if x := builder.Tasks[1]; !reflect.DeepEqual(x, &ShellTask{
   490  		LineNum:              4,
   491  		ID:                   2,
   492  		ShellScript:          "test examples/helloprint.c",
   493  		DependentFiles:       flowscript.NewStringSetWithValues("examples/helloprint.c"),
   494  		CreatingFiles:        flowscript.NewStringSet(),
   495  		DependentTaskID:      []int{},
   496  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   497  	}) {
   498  		t.Fatalf("Invalid task:%s", x)
   499  	}
   500  
   501  	if x := builder.Tasks[2]; !reflect.DeepEqual(x, &ShellTask{
   502  		LineNum:              4,
   503  		ID:                   3,
   504  		ShellScript:          "test 1 value 3",
   505  		DependentFiles:       flowscript.NewStringSetWithValues("1 value 3"),
   506  		CreatingFiles:        flowscript.NewStringSet(),
   507  		DependentTaskID:      []int{},
   508  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   509  	}) {
   510  		t.Fatalf("Invalid task:%s", x)
   511  	}
   512  }
   513  
   514  func TestParseShellflowBlock4(t *testing.T) {
   515  	testScript := `#!/usr/bin/shellflow
   516  #% a = [1, 2, 3]
   517  #% b = [4, 5, 6]
   518  for y in {{zip(a, b)}}; do
   519      test {{y[0]}} / {{y[1]}}
   520  done
   521  `
   522  	reader := strings.NewReader(testScript)
   523  	env := NewEnvironment()
   524  	block, content, err := ParseShellflowBlock(reader, env)
   525  	if err != nil {
   526  		t.Fatalf("Error: %s", err.Error())
   527  	}
   528  	if content != testScript {
   529  		t.Fatalf("Invalid content: %s", content)
   530  	}
   531  
   532  	assign1, err := NewSingleFlowScriptTask(2, "#% a = [1, 2, 3]")
   533  	if err != nil {
   534  		t.Fatalf("Failed to parse: %s", err.Error())
   535  	}
   536  	assign2, err := NewSingleFlowScriptTask(3, "#% b = [4, 5, 6]")
   537  	if err != nil {
   538  		t.Fatalf("Failed to parse: %s", err.Error())
   539  	}
   540  
   541  	parsedTest, err := NewSingleShellTask(5, "test {{y[0]}} / {{y[1]}}")
   542  	if err != nil {
   543  		t.Fatalf("Failed to parse: %s", err.Error())
   544  	}
   545  
   546  	parsedVal, err := flowscript.ParseScript("zip(a, b)")
   547  	if err != nil {
   548  		t.Fatalf("Failed to parse: %s", err.Error())
   549  	}
   550  
   551  	expected := &SimpleTaskBlock{
   552  		LineNum: 1,
   553  		SubTask: []FlowTask{
   554  			assign1,
   555  			assign2,
   556  			&ForFlowTask{
   557  				LineNum:      4,
   558  				VariableName: "y",
   559  				Items:        []ForItem{EvaluableForItem{parsedVal}},
   560  				SubTask:      []FlowTask{parsedTest},
   561  			},
   562  		},
   563  	}
   564  
   565  	if !reflect.DeepEqual(block, expected) {
   566  		d, e := json.MarshalIndent(block, "", "  ")
   567  		if e != nil {
   568  			t.Fatalf("bad block and no json: %s", e.Error())
   569  		}
   570  
   571  		d2, e := json.MarshalIndent(expected, "", "  ")
   572  		if e != nil {
   573  			t.Fatalf("bad block and no json: %s", e.Error())
   574  		}
   575  		t.Fatalf("Bad block: %s / %s", d, d2)
   576  	}
   577  
   578  	builder, err := NewShellTaskBuilder()
   579  	if err != nil {
   580  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   581  	}
   582  
   583  	err = block.Subscribe(env.flowEnvironment, builder)
   584  	if err != nil {
   585  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   586  	}
   587  
   588  	if len(builder.Tasks) != 3 {
   589  		t.Fatalf("Invalid number of tasks: %d", len(builder.Tasks))
   590  	}
   591  
   592  	if x := builder.Tasks[0]; !reflect.DeepEqual(x, &ShellTask{
   593  		LineNum:              5,
   594  		ID:                   1,
   595  		ShellScript:          "test 1 / 4",
   596  		DependentFiles:       flowscript.NewStringSet(),
   597  		CreatingFiles:        flowscript.NewStringSet(),
   598  		DependentTaskID:      []int{},
   599  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   600  	}) {
   601  		t.Fatalf("Invalid task:%s", x)
   602  	}
   603  
   604  	if x := builder.Tasks[1]; !reflect.DeepEqual(x, &ShellTask{
   605  		LineNum:              5,
   606  		ID:                   2,
   607  		ShellScript:          "test 2 / 5",
   608  		DependentFiles:       flowscript.NewStringSet(),
   609  		CreatingFiles:        flowscript.NewStringSet(),
   610  		DependentTaskID:      []int{},
   611  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   612  	}) {
   613  		t.Fatalf("Invalid task:%s", x)
   614  	}
   615  
   616  	if x := builder.Tasks[2]; !reflect.DeepEqual(x, &ShellTask{
   617  		LineNum:              5,
   618  		ID:                   3,
   619  		ShellScript:          "test 3 / 6",
   620  		DependentFiles:       flowscript.NewStringSet(),
   621  		CreatingFiles:        flowscript.NewStringSet(),
   622  		DependentTaskID:      []int{},
   623  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   624  	}) {
   625  		t.Fatalf("Invalid task:%s", x)
   626  	}
   627  }
   628  
   629  func TestParseShellflowBlock5(t *testing.T) {
   630  	testScript := `#!/usr/bin/shellflow
   631  #% a = [1, 2]
   632  #% b = [4, 5]
   633  for y in {{zip(a, b)}}; do
   634      for z in {{y}}; do
   635          test {{z}}
   636      done
   637  done
   638  `
   639  	reader := strings.NewReader(testScript)
   640  	env := NewEnvironment()
   641  	block, content, err := ParseShellflowBlock(reader, env)
   642  	if err != nil {
   643  		t.Fatalf("Error: %s", err.Error())
   644  	}
   645  	if content != testScript {
   646  		t.Fatalf("Invalid content: %s", content)
   647  	}
   648  
   649  	assign1, err := NewSingleFlowScriptTask(2, "#% a = [1, 2]")
   650  	if err != nil {
   651  		t.Fatalf("Failed to parse: %s", err.Error())
   652  	}
   653  	assign2, err := NewSingleFlowScriptTask(3, "#% b = [4, 5]")
   654  	if err != nil {
   655  		t.Fatalf("Failed to parse: %s", err.Error())
   656  	}
   657  
   658  	parsedTest, err := NewSingleShellTask(6, "test {{z}}")
   659  	if err != nil {
   660  		t.Fatalf("Failed to parse: %s", err.Error())
   661  	}
   662  
   663  	parsedVal1, err := flowscript.ParseScript("zip(a, b)")
   664  	if err != nil {
   665  		t.Fatalf("Failed to parse: %s", err.Error())
   666  	}
   667  
   668  	parsedVal2, err := flowscript.ParseScript("y")
   669  	if err != nil {
   670  		t.Fatalf("Failed to parse: %s", err.Error())
   671  	}
   672  
   673  	expected := &SimpleTaskBlock{
   674  		LineNum: 1,
   675  		SubTask: []FlowTask{
   676  			assign1,
   677  			assign2,
   678  			&ForFlowTask{
   679  				LineNum:      4,
   680  				VariableName: "y",
   681  				Items:        []ForItem{EvaluableForItem{parsedVal1}},
   682  				SubTask: []FlowTask{
   683  					&ForFlowTask{
   684  						LineNum:      5,
   685  						VariableName: "z",
   686  						Items:        []ForItem{EvaluableForItem{parsedVal2}},
   687  						SubTask:      []FlowTask{parsedTest},
   688  					},
   689  				},
   690  			},
   691  		},
   692  	}
   693  
   694  	if !reflect.DeepEqual(block, expected) {
   695  		d, e := json.MarshalIndent(block, "", "  ")
   696  		if e != nil {
   697  			t.Fatalf("bad block and no json: %s", e.Error())
   698  		}
   699  
   700  		d2, e := json.MarshalIndent(expected, "", "  ")
   701  		if e != nil {
   702  			t.Fatalf("bad block and no json: %s", e.Error())
   703  		}
   704  		t.Fatalf("Bad block: %s / %s", d, d2)
   705  	}
   706  
   707  	builder, err := NewShellTaskBuilder()
   708  	if err != nil {
   709  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   710  	}
   711  
   712  	err = block.Subscribe(env.flowEnvironment, builder)
   713  	if err != nil {
   714  		t.Fatalf("failed to create shell task builder: %s", err.Error())
   715  	}
   716  
   717  	if len(builder.Tasks) != 4 {
   718  		t.Fatalf("Invalid number of tasks: %d", len(builder.Tasks))
   719  	}
   720  
   721  	if x := builder.Tasks[0]; !reflect.DeepEqual(x, &ShellTask{
   722  		LineNum:              6,
   723  		ID:                   1,
   724  		ShellScript:          "test 1",
   725  		DependentFiles:       flowscript.NewStringSet(),
   726  		CreatingFiles:        flowscript.NewStringSet(),
   727  		DependentTaskID:      []int{},
   728  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   729  	}) {
   730  		t.Fatalf("Invalid task:%s", x)
   731  	}
   732  
   733  	if x := builder.Tasks[1]; !reflect.DeepEqual(x, &ShellTask{
   734  		LineNum:              6,
   735  		ID:                   2,
   736  		ShellScript:          "test 4",
   737  		DependentFiles:       flowscript.NewStringSet(),
   738  		CreatingFiles:        flowscript.NewStringSet(),
   739  		DependentTaskID:      []int{},
   740  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   741  	}) {
   742  		t.Fatalf("Invalid task:%s", x)
   743  	}
   744  
   745  	if x := builder.Tasks[2]; !reflect.DeepEqual(x, &ShellTask{
   746  		LineNum:              6,
   747  		ID:                   3,
   748  		ShellScript:          "test 2",
   749  		DependentFiles:       flowscript.NewStringSet(),
   750  		CreatingFiles:        flowscript.NewStringSet(),
   751  		DependentTaskID:      []int{},
   752  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   753  	}) {
   754  		t.Fatalf("Invalid task:%s", x)
   755  	}
   756  
   757  	if x := builder.Tasks[3]; !reflect.DeepEqual(x, &ShellTask{
   758  		LineNum:              6,
   759  		ID:                   4,
   760  		ShellScript:          "test 5",
   761  		DependentFiles:       flowscript.NewStringSet(),
   762  		CreatingFiles:        flowscript.NewStringSet(),
   763  		DependentTaskID:      []int{},
   764  		CommandConfiguration: CommandConfiguration{SGEOption: []string{}},
   765  	}) {
   766  		t.Fatalf("Invalid task:%s", x)
   767  	}
   768  }
   769  
   770  func TestForItemSplit(t *testing.T) {
   771  	if x := forItemSplit("a b c"); !reflect.DeepEqual(x, []string{"a", "b", "c"}) {
   772  		t.Fatalf("bad split result %s", x)
   773  	}
   774  
   775  	if x := forItemSplit("  a b c"); !reflect.DeepEqual(x, []string{"a", "b", "c"}) {
   776  		t.Fatalf("bad split result %s", x)
   777  	}
   778  
   779  	if x := forItemSplit("a b c  "); !reflect.DeepEqual(x, []string{"a", "b", "c"}) {
   780  		t.Fatalf("bad split result %s", x)
   781  	}
   782  
   783  	if x := forItemSplit(" abc efg hij "); !reflect.DeepEqual(x, []string{"abc", "efg", "hij"}) {
   784  		t.Fatalf("bad split result %s", x)
   785  	}
   786  
   787  	if x := forItemSplit("{{[1, 2, 3, 4, 5]}}"); !reflect.DeepEqual(x, []string{"{{[1, 2, 3, 4, 5]}}"}) {
   788  		t.Fatalf("bad split result %s", x)
   789  	}
   790  
   791  	if x := forItemSplit("  {{[1, 2, 3, 4, 5]}}   "); !reflect.DeepEqual(x, []string{"{{[1, 2, 3, 4, 5]}}"}) {
   792  		t.Fatalf("bad split result %s", x)
   793  	}
   794  
   795  	if x := forItemSplit("a  {{[1, 2, 3, 4, 5]}}   c"); !reflect.DeepEqual(x, []string{"a", "{{[1, 2, 3, 4, 5]}}", "c"}) {
   796  		t.Fatalf("bad split result %s", x)
   797  	}
   798  
   799  	if x := forItemSplit("a  {{[1, 2, 3, 4, 5] "); !reflect.DeepEqual(x, []string{"a", "{{[1, 2, 3, 4, 5] "}) {
   800  		t.Fatalf("bad split result %s", x)
   801  	}
   802  }