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 }