github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/forth/forth_test.go (about) 1 // Copyright 2018 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 forth 6 7 import ( 8 "errors" 9 "os" 10 "strconv" 11 "testing" 12 ) 13 14 type forthTest struct { 15 val string 16 res Cell 17 err error 18 empty bool 19 } 20 21 var forthTests = []forthTest{ 22 {val: "hostname", res: "", empty: true}, 23 {val: "2", res: "2", empty: true}, 24 {val: "2 2 +", res: "4", empty: true}, 25 {val: "4 2 -", res: "2", empty: true}, 26 {val: "4 2 *", res: "8", empty: true}, 27 {val: "4 2 /", res: "2", empty: true}, 28 {val: "5 2 %", res: "1", empty: true}, 29 {val: "sb43 hostbase", res: "43", empty: true}, 30 {val: "sb43 hostbase dup 20 / swap 20 % dup ifelse", res: "3", empty: true}, 31 {val: "sb40 hostbase dup 20 / swap 20 % dup ifelse", res: "2", empty: true}, 32 {val: "2 4 swap /", res: "2", empty: true}, 33 {val: "0 1 1 ifelse", res: "1", empty: true}, 34 {val: "0 1 0 ifelse", res: "0", empty: true}, 35 {val: "str cat strcat", res: "strcat", empty: true}, 36 {val: "1 dup +", res: "2", empty: true}, 37 {val: "4095 4096 roundup", res: "4096", empty: true}, 38 {val: "4097 8192 roundup", res: "8192", empty: true}, 39 {val: "2 x +", res: "2", err: strconv.ErrSyntax, empty: false}, 40 {val: "1 dd +", res: "2", empty: true}, 41 {val: "1 d3d", res: "3", empty: true}, 42 {val: "drop", res: "", err: ErrEmptyStack, empty: true}, 43 {val: "5 5 + hostbase", res: "", err: strconv.ErrSyntax, empty: true}, 44 {val: "1 1 '+ newword 1 1 '+ newword", res: "", err: ErrWordExist, empty: true}, 45 {val: "1 4 bad newword", res: "", err: ErrNotEnoughElements, empty: false}, 46 } 47 48 func TestForth(t *testing.T) { 49 forthTests[0].res, _ = os.Hostname() 50 f := New() 51 if f.Length() != 0 { 52 t.Errorf("Test: stack is %d and should be 0", f.Length()) 53 } 54 if f.Empty() != true { 55 t.Errorf("Test: stack is %v and should be false", f.Empty()) 56 } 57 f.Push("test") 58 if f.Length() != 1 { 59 t.Errorf("Test: stack is %d and should be 1", f.Length()) 60 } 61 if f.Empty() == true { 62 t.Errorf("Test: stack is %v and should be false", f.Empty()) 63 } 64 f.Reset() 65 if f.Length() != 0 { 66 t.Errorf("Test: After Reset(): stack is %d and should be 0", f.Length()) 67 } 68 if f.Empty() != true { 69 t.Errorf("Test: After Reset(): stack is %v and should be true", f.Empty()) 70 } 71 NewWord(f, "dd", "dup") 72 NewWord(f, "d3d", "dup", "dup", "+", "+") 73 for i, tt := range forthTests { 74 var err error 75 res, err := EvalPop(f, tt.val) 76 t.Logf("tt %v res %v err %v", tt, res, err) 77 if res == tt.res || errors.Is(err, tt.err) { 78 t.Logf("Test: '%v' '%v' '%v': Pass\n", tt.val, res, err) 79 } else { 80 t.Errorf("Test %d: '%v' got (%v, %v): want (%v, %v): Fail\n", i, tt.val, res, err, tt.res, tt.err) 81 t.Logf("ops %v\n", Ops()) 82 continue 83 } 84 if f.Empty() != tt.empty { 85 t.Errorf("Test %d: %v: stack is %v and should be %v", i, tt, f.Empty(), tt.empty) 86 } 87 /* stack may not be right; reset it. */ 88 f.Reset() 89 } 90 } 91 92 func TestBadPop(t *testing.T) { 93 var b [3]byte 94 f := New() 95 f.Push(b) 96 res, err := EvalPop(f, "2 +") 97 t.Logf("%v, %v", res, err) 98 if !errors.Is(err, strconv.ErrSyntax) { 99 t.Errorf("got %v, want %v", err, strconv.ErrSyntax) 100 } 101 if res != nil { 102 t.Errorf("got %v, want nil", res) 103 } 104 } 105 106 func TestOpmap(t *testing.T) { 107 f := New() 108 err := Eval(f, "words") 109 if err != nil { 110 t.Fatalf("words: got %v, nil", err) 111 } 112 if f.Length() != 1 { 113 t.Fatalf("words: got length %d, want 1", f.Length()) 114 } 115 w := f.Pop() 116 switch w.(type) { 117 case []string: 118 default: 119 t.Fatalf("words: got %T, want []string", w) 120 } 121 t.Logf("words are %v", w) 122 } 123 124 func TestNewWord(t *testing.T) { 125 Debug = t.Logf 126 f := New() 127 // This test creates a word, tp, with 3 args, which simply 128 // pushes 1 and 3 on the stack and applies +. 129 // Note the use of ' so we can evaluate + as a string, 130 // not an operator. 131 err := Eval(f, "1", "3", "'+", "3", "tp", "newword") 132 if err != nil { 133 t.Fatalf("newword: got %v, nil", err) 134 } 135 err = Eval(f, "tp") 136 if err != nil { 137 t.Fatalf("newword: got %v, want nil", err) 138 } 139 t.Logf("stack %v", f.Stack()) 140 } 141 142 // make sure that if we die in an Eval nested in an Eval, we fall all the way 143 // back out. 144 func TestEvalPanic(t *testing.T) { 145 f := New() 146 Debug = t.Logf 147 err := Eval(f, "0", "'+", "2", "p", "newword") 148 if err != nil { 149 t.Fatalf("newword: got %v, nil", err) 150 } 151 t.Logf("p created, now try problems") 152 err = Eval(f, "0", uint8(0), "+") 153 if err == nil { 154 t.Fatal("Got nil, want error") 155 } 156 t.Logf("Test plus with wrong types: %v", err) 157 f.Reset() 158 err = Eval(f, "p") 159 if err == nil { 160 t.Fatal("P with too few args: Got nil, want error") 161 } 162 t.Logf("p with too few args: %v", err) 163 err2 := Eval(f, "p", "0", uint8(0), "+") 164 if err2.Error() != err.Error() { 165 t.Fatalf("Got %v, want %v", err2, err) 166 } 167 }