github.com/igggame/nebulas-go@v2.1.0+incompatible/cmd/console/console_test.go (about) 1 package console 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/peterh/liner" 12 ) 13 14 type tester struct { 15 console *Console 16 input *hookedPrompter 17 output *bytes.Buffer 18 } 19 20 type hookedPrompter struct { 21 scheduler chan string 22 } 23 24 // Prompt shows the prompt and requests text input 25 // returning the input. 26 func (p *hookedPrompter) Prompt(prompt string) (string, error) { 27 // Send the prompt to the tester 28 select { 29 case p.scheduler <- prompt: 30 case <-time.After(time.Second): 31 return "", errors.New("prompt timeout") 32 } 33 // Retrieve the response and feed to the console 34 select { 35 case input := <-p.scheduler: 36 return input, nil 37 case <-time.After(time.Second): 38 return "", errors.New("input timeout") 39 } 40 } 41 42 // PromptPassphrase shows the prompt and request passphrase text input, the passphrase 43 // not show, returns the passphrase 44 func (p *hookedPrompter) PromptPassphrase(prompt string) (passwd string, err error) { 45 return "", nil 46 } 47 48 // PromptConfirm shows the prompt to the user and requests a boolean 49 // choice to be made, returning that choice. 50 func (p *hookedPrompter) PromptConfirm(prompt string) (bool, error) { 51 input, err := p.Prompt(prompt + " [y/N] ") 52 if len(input) > 0 && strings.ToUpper(input[:1]) == "Y" { 53 return true, nil 54 } 55 return false, err 56 } 57 58 // SetHistory sets the history that the prompter will allow 59 // the user to scroll back to. 60 func (p *hookedPrompter) SetHistory(history []string) { 61 //fmt.Println("to be implemented sethistory") 62 } 63 64 // AppendHistory appends an entry to the scrollback history. 65 func (p *hookedPrompter) AppendHistory(command string) { 66 //fmt.Println("to be implemented AppendHistory") 67 } 68 69 // SetWordCompleter sets the completion function that the prompter will call to 70 // fetch completion candidates when the user presses tab. 71 func (p *hookedPrompter) SetWordCompleter(completer liner.WordCompleter) { 72 //fmt.Println("to be implemented SetWordCompleter") 73 } 74 75 func (env *tester) Close(t *testing.T) { 76 } 77 78 func newTester(t *testing.T) *tester { 79 80 hookedInput := &hookedPrompter{scheduler: make(chan string)} 81 hookedOutput := new(bytes.Buffer) 82 83 testConsole := New(Config{ 84 Prompter: hookedInput, 85 PrompterCh: make(chan string), 86 Writer: hookedOutput, 87 Neb: nil, 88 }) 89 90 return &tester{ 91 console: testConsole, 92 input: hookedInput, 93 output: hookedOutput, 94 } 95 } 96 97 // Tests that the console can be used in interactive mode 98 func TestConsoleInteractive(t *testing.T) { 99 tester := newTester(t) 100 defer tester.Close(t) 101 go tester.console.Interactive() 102 103 // Wait for a promt and send a statement back 104 select { 105 case <-tester.input.scheduler: 106 case <-time.After(time.Second): 107 t.Fatalf("initial prompt timeout") 108 } 109 110 select { 111 case tester.input.scheduler <- "obj = {expect: 2+2}": 112 case <-time.After(time.Second): 113 t.Fatalf("input feedback timeout") 114 } 115 116 // Wait for the second promt and ensure first statement was evaluated 117 select { 118 case <-tester.input.scheduler: 119 case <-time.After(time.Second): 120 t.Fatalf("thirt prompt timeout") 121 } 122 123 output := tester.output.String() 124 if !strings.Contains(output, "4") { 125 t.Fatalf("statement evaluation failed: have %s, want %s", output, "4") 126 } 127 } 128 129 // Test pre cmd can be run 130 func TestRun(t *testing.T) { 131 tester := newTester(t) 132 defer tester.Close(t) 133 tester.console.jsvm.Run(`var preloaded_var = "some_preloaded_var"`) 134 tester.console.Evaluate("preloaded_var") 135 output := tester.output.String() 136 if !strings.Contains(output, "some_preloaded_var") { 137 t.Fatalf("preloaded variable missing: have %s, want %s", output, "some-preloaded-string") 138 } 139 } 140 141 // Tests that JavaScript statement evaluation works as intended. 142 func TestEvaluate(t *testing.T) { 143 tester := newTester(t) 144 defer tester.Close(t) 145 146 tester.console.Evaluate("'abc'+'bcd'") 147 if output := tester.output.String(); !strings.Contains(output, "abcbcd") { 148 t.Fatalf("statement evaluation failed: have %s, want %s", output, "abcbcd") 149 } 150 } 151 152 // Tests that the JavaScript objects returned by statement executions are properly 153 // pretty printed instead of just displaying "[object]". 154 155 func TestPrettyPrint(t *testing.T) { 156 tester := newTester(t) 157 defer tester.Close(t) 158 159 tester.console.Evaluate("obj = {int: 1, string: 'i am a string', list: [3, 3], obj: {null:null}}") 160 161 // Assemble the actual output we're after and verify 162 want := `{ 163 "int": 1, 164 "list": [ 165 3, 166 3 167 ], 168 "obj": { 169 "null": null 170 }, 171 "string": "i am a string" 172 } 173 ` 174 if output := tester.output.String(); output != want { 175 t.Fatalf("pretty print mismatch: have %s, want %s", output, want) 176 } 177 } 178 179 // Tests that the console can handle valid commands (no arguments) 180 func TestApiValidInput(t *testing.T) { 181 tester := newTester(t) 182 defer tester.Close(t) 183 go tester.console.Interactive() 184 185 testCases := []struct { 186 inputCommand string 187 expectOutputWhenNebRunning string 188 // when local neb is not started only get expectOutputWhenNebNotRunning 189 expectOutputWhenNebNotRunning string 190 }{ 191 /* {`admin.accounts()`, "\"addresses\"", "connection refuse"}, */ // TODO: @cheng recover 192 /* {`admin.nodeInfo()`, "\"bucket_size\"", "connection refuse"}, */ 193 /* {`api.blockDump()`, "\"data\"", "connection refuse"}, */ 194 {`api.gasPrice()`, "\"gas_price\"", "connection refuse"}, 195 {`api.getNebState()`, "\"chain_id\"", "connection refuse"}, 196 } 197 198 // Wait for a promt and send a statement back 199 select { 200 case <-tester.input.scheduler: 201 case <-time.After(time.Second): 202 t.Fatalf("initial prompt timeout") 203 } 204 205 for _, tt := range testCases { 206 fmt.Println("testing " + tt.inputCommand) 207 208 select { 209 case tester.input.scheduler <- tt.inputCommand: 210 case <-time.After(time.Second): 211 t.Fatalf("input feedback timeout") 212 } 213 // Wait for the second promt and ensure first statement was evaluated 214 select { 215 case <-tester.input.scheduler: 216 case <-time.After(time.Second * 2): 217 t.Fatalf("secondary prompt timeout") 218 } 219 220 output := tester.output.String() 221 222 // Reset resets the buffer to make it has no content 223 tester.output.Reset() 224 225 if strings.Contains(output, tt.expectOutputWhenNebRunning) { 226 continue 227 } else if strings.Contains(output, tt.expectOutputWhenNebNotRunning) { 228 fmt.Println("testing console without running neb") 229 } else { 230 t.Fatalf("statement evaluation failed: have %s, want %s", output, tt.expectOutputWhenNebRunning+" or "+tt.expectOutputWhenNebNotRunning) 231 } 232 } 233 } 234 235 func TestSpecialInput(t *testing.T) { 236 tester := newTester(t) 237 defer tester.Close(t) 238 go tester.console.Interactive() 239 240 testCases := []struct { 241 inputCommand string 242 expectOutputWhenNebRunning string 243 // when local neb is not started only get expectOutputWhenNebNotRunning 244 expectOutputWhenNebNotRunning string 245 }{ 246 {`#(*$)@(*#$)(*$`, `\"Unexpected token ILLEGAL\"`, "Unexpected token ILLEGAL"}, 247 {``, "", ""}, 248 {`alert("Hello! I am an alert box!!");`, "alert' is not defined", "alert' is not defined"}, 249 {`admin.unknownCommand();`, "unknownCommand' is not a function", "unknownCommand' is not a function"}, 250 } 251 // Wait for a promt and send a statement back 252 select { 253 case <-tester.input.scheduler: 254 case <-time.After(time.Second): 255 t.Fatalf("initial prompt timeout") 256 } 257 258 for _, tt := range testCases { 259 fmt.Println("testing " + tt.inputCommand) 260 261 select { 262 case tester.input.scheduler <- tt.inputCommand: 263 case <-time.After(time.Second): 264 t.Fatalf("input feedback timeout") 265 } 266 // Wait for the second promt and ensure first statement was evaluated 267 select { 268 case <-tester.input.scheduler: 269 case <-time.After(time.Second): 270 t.Fatalf("secondary prompt timeout") 271 } 272 273 output := tester.output.String() 274 275 // Reset resets the buffer to make it has no content 276 tester.output.Reset() 277 278 if strings.Contains(output, tt.expectOutputWhenNebRunning) { 279 continue 280 } else if strings.Contains(output, tt.expectOutputWhenNebNotRunning) { 281 fmt.Println("testing console without running neb") 282 } else { 283 t.Fatalf("statement evaluation failed: have %s, want %s", output, tt.expectOutputWhenNebRunning+" or "+tt.expectOutputWhenNebNotRunning) 284 } 285 } 286 }