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  }