github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/exp/rush/parse_test.go (about)

     1  // Copyright 2022 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"reflect"
    14  	"testing"
    15  )
    16  
    17  func compare(got, want []*Command) error {
    18  	if len(got) != len(want) {
    19  		return fmt.Errorf("got %d commands, want %d commands", len(got), len(want))
    20  	}
    21  	for i := range got {
    22  		g := got[i]
    23  		w := want[i]
    24  		if len(g.Args) != len(w.Args) {
    25  			return fmt.Errorf("%q: Got %d Args, want %d Args", g, len(g.Args), len(w.Args))
    26  		}
    27  		if !reflect.DeepEqual(g.Args, w.Args) {
    28  			return fmt.Errorf("%q: got %q commands, want %q commands", g, g.Args, w.Args)
    29  		}
    30  		if g.Link != w.Link {
    31  			return fmt.Errorf("%q: Link is %q, want %q", g, g.Link, w.Link)
    32  		}
    33  		if g.BG != w.BG {
    34  			return fmt.Errorf("%q: BG is %v, want %v", g, g.BG, w.BG)
    35  		}
    36  		// Just check simple stdin/out redirection.
    37  		if g.fdmap[1] != w.fdmap[1] {
    38  			return fmt.Errorf("%q: fdmap[1] is %v, want %v", g, g.fdmap[1], w.fdmap[1])
    39  		}
    40  		if g.fdmap[0] != w.fdmap[0] {
    41  			return fmt.Errorf("%q: fdmap[0] is %v, want %v", g, g.fdmap[0], w.fdmap[0])
    42  		}
    43  	}
    44  	return nil
    45  }
    46  func TestParsing(t *testing.T) {
    47  
    48  	var tests = []struct {
    49  		name string
    50  		line string
    51  		c    []*Command
    52  		typ  string
    53  		err  error
    54  	}{
    55  		{name: "EOF", line: "", c: []*Command{}, typ: "EOF", err: io.EOF},
    56  		{name: "singlequote", line: "'gadate a'", c: []*Command{
    57  			{Args: []arg{{"gadate a", "ARG"}}, Link: "", BG: false},
    58  		}, typ: "EOF", err: io.EOF},
    59  		{name: "backslash", line: "\\\\\\gadate", c: []*Command{
    60  			{Args: []arg{{"\\gadate", "ARG"}}, Link: "", BG: false},
    61  		}, typ: "EOF", err: io.EOF},
    62  		{name: "env", line: "adate $a", c: []*Command{
    63  			{Args: []arg{{"adate", "ARG"}, {"a", "ARG"}}, Link: "", BG: false},
    64  		}, typ: "EOF", err: io.EOF},
    65  		{name: "No EOL", line: "adate", c: []*Command{
    66  			{Args: []arg{{"adate", "ARG"}}, Link: "", BG: false},
    67  		}, typ: "EOF", err: io.EOF},
    68  		{name: "redir>/dev/null", line: "redir > /dev/null", c: []*Command{
    69  			{Args: []arg{{"redir", "ARG"}}, Link: "", BG: false, fdmap: map[int]string{1: "/dev/null"}},
    70  		}, typ: "EOF", err: io.EOF},
    71  		{name: "redir</dev/null", line: "redir</dev/null", c: []*Command{
    72  			{Args: []arg{{"redir", "ARG"}}, Link: "", BG: false, fdmap: map[int]string{0: "/dev/null"}},
    73  		}, typ: "EOF", err: io.EOF},
    74  		{name: "Single", line: "adate\n", c: []*Command{
    75  			{Args: []arg{{"adate", "ARG"}}, Link: "", BG: false},
    76  		}, typ: "EOL", err: nil},
    77  		{name: "BG", line: "adate&\n", c: []*Command{
    78  			{Args: []arg{{"adate", "ARG"}}, Link: "", BG: true},
    79  		}, typ: "EOL", err: nil},
    80  		{name: "BG", line: "adate&", c: []*Command{
    81  			{Args: []arg{{"adate", "ARG"}}, Link: "", BG: true},
    82  		}, typ: "EOF", err: nil},
    83  		{name: "one BG one not", line: "adate&bdate\n", c: []*Command{
    84  			{Args: []arg{{"adate", "ARG"}}, Link: "", BG: true},
    85  			{Args: []arg{{"bdate", "ARG"}}, Link: "", BG: false},
    86  		}, typ: "EOL", err: nil},
    87  		{name: "two BG", line: "adate&bdate&\n", c: []*Command{
    88  			{Args: []arg{{"adate", "ARG"}}, Link: "", BG: true},
    89  			{Args: []arg{{"bdate", "ARG"}}, Link: "", BG: true},
    90  		}, typ: "EOL", err: nil},
    91  		{name: "AND", line: "adate&&bdate\n", c: []*Command{
    92  			{Args: []arg{{"adate", "ARG"}}, Link: "&&"},
    93  			{Args: []arg{{"bdate", "ARG"}}, Link: ""},
    94  		}, typ: "EOL", err: nil},
    95  		{name: "OR", line: "adate||bdate\n", c: []*Command{
    96  			{Args: []arg{{"adate", "ARG"}}, Link: "||"},
    97  			{Args: []arg{{"bdate", "ARG"}}, Link: ""},
    98  		}, typ: "EOL", err: nil},
    99  		{name: "BG_OR", line: "zdate & adate||bdate\n", c: []*Command{
   100  			{Args: []arg{{"zdate", "ARG"}}, Link: "", BG: true},
   101  			{Args: []arg{{"adate", "ARG"}}, Link: "||"},
   102  			{Args: []arg{{"bdate", "ARG"}}, Link: ""},
   103  		}, typ: "EOL", err: nil},
   104  		{name: "BG_PIPE", line: "zdate & adate|bdate\n", c: []*Command{
   105  			{Args: []arg{{"zdate", "ARG"}}, Link: "", BG: true},
   106  			{Args: []arg{{"adate", "ARG"}}, Link: "|"},
   107  			{Args: []arg{{"bdate", "ARG"}}, Link: ""},
   108  		}, typ: "EOL", err: nil},
   109  		{name: "BG_PIPE_AND", line: "zdate & adate|bdate&&cdate\n", c: []*Command{
   110  			{Args: []arg{{"zdate", "ARG"}}, Link: "", BG: true},
   111  			{Args: []arg{{"adate", "ARG"}}, Link: "|"},
   112  			{Args: []arg{{"bdate", "ARG"}}, Link: "&&"},
   113  			{Args: []arg{{"cdate", "ARG"}}, Link: ""},
   114  		}, typ: "EOL", err: nil},
   115  	}
   116  
   117  	for _, tt := range tests {
   118  		c, typ, err := getCommand(bufio.NewReader(bytes.NewReader([]byte(tt.line))))
   119  		if err != nil && !errors.Is(err, tt.err) {
   120  			t.Errorf("%s: getCommand(%q): %v is not %v", tt.name, tt.line, err, tt.err)
   121  			continue
   122  		}
   123  		if typ != tt.typ {
   124  			t.Errorf("%s: getCommand(%q): got %s want %s", tt.name, tt.line, typ, tt.typ)
   125  			continue
   126  		}
   127  		// We don't test broken parsing here, just that we get some expected
   128  		// arrays
   129  		doArgs(c)
   130  		if err := commands(c); err != nil {
   131  			t.Errorf("commands: %v != nil", err)
   132  			continue
   133  		}
   134  		if err := wire(c); err != nil {
   135  			t.Errorf("wire: %v != nil", err)
   136  			continue
   137  		}
   138  		for _, cmd := range c {
   139  			t.Logf("{Args: %q, Link: %q, BG: %v, fdmap: %v},", cmd.Args, cmd.Link, cmd.BG, cmd.fdmap)
   140  		}
   141  		if err := compare(c, tt.c); err != nil {
   142  			t.Errorf("%s: getCommand(%q): %v", tt.name, tt.line, err)
   143  		}
   144  
   145  	}
   146  }