github.com/elves/elvish@v0.15.0/pkg/edit/prompt_test.go (about) 1 package edit 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/elves/elvish/pkg/cli/clitest" 9 "github.com/elves/elvish/pkg/cli/term" 10 "github.com/elves/elvish/pkg/testutil" 11 "github.com/elves/elvish/pkg/ui" 12 ) 13 14 func TestPrompt_ValueOutput(t *testing.T) { 15 f := setup(rc(`edit:prompt = { put '#'; float64 13; styled '> ' red }`)) 16 defer f.Cleanup() 17 18 f.TestTTY(t, 19 "#13> ", Styles, 20 " !!", term.DotHere) 21 } 22 23 func TestPrompt_ByteOutput(t *testing.T) { 24 f := setup(rc(`edit:prompt = { print 'bytes> ' }`)) 25 defer f.Cleanup() 26 27 f.TestTTY(t, "bytes> ", term.DotHere) 28 } 29 30 func TestPrompt_ParsesSGRInByteOutput(t *testing.T) { 31 f := setup(rc(`edit:prompt = { print "\033[31mred\033[m> " }`)) 32 defer f.Cleanup() 33 34 f.TestTTY(t, 35 "red> ", Styles, 36 "!!! ", term.DotHere) 37 } 38 39 func TestPrompt_NotifiesInvalidValueOutput(t *testing.T) { 40 f := setup(rc(`edit:prompt = { put good [bad] good2 }`)) 41 defer f.Cleanup() 42 43 f.TestTTY(t, "goodgood2", term.DotHere) 44 f.TestTTYNotes(t, "invalid output type from prompt: list") 45 } 46 47 func TestPrompt_NotifiesException(t *testing.T) { 48 f := setup(rc(`edit:prompt = { fail ERROR }`)) 49 defer f.Cleanup() 50 51 f.TestTTYNotes(t, 52 "[prompt error] ERROR\n", 53 `see stack trace with "show $edit:exceptions[0]"`) 54 evals(f.Evaler, `excs = (count $edit:exceptions)`) 55 testGlobal(t, f.Evaler, "excs", "1") 56 } 57 58 func TestRPrompt(t *testing.T) { 59 f := setup(rc(`edit:rprompt = { put 'RRR' }`)) 60 defer f.Cleanup() 61 62 f.TestTTY(t, "~> ", term.DotHere, 63 strings.Repeat(" ", clitest.FakeTTYWidth-6)+"RRR") 64 } 65 66 func TestPromptEagerness(t *testing.T) { 67 f := setup(rc( 68 `i = 0`, 69 `edit:prompt = { i = (+ $i 1); put $i'> ' }`, 70 `edit:-prompt-eagerness = 10`)) 71 defer f.Cleanup() 72 73 f.TestTTY(t, "1> ", term.DotHere) 74 // With eagerness = 10, any key press will cause the prompt to be 75 // recomputed. 76 f.TTYCtrl.Inject(term.K(ui.Backspace)) 77 f.TestTTY(t, "2> ", term.DotHere) 78 } 79 80 func TestPromptStaleThreshold(t *testing.T) { 81 f := setup(rc( 82 `pipe = (pipe)`, 83 `edit:prompt = { nop (slurp < $pipe); put '> ' }`, 84 `edit:prompt-stale-threshold = `+scaledMsAsSec(50))) 85 defer f.Cleanup() 86 87 f.TestTTY(t, 88 "???> ", Styles, 89 "+++++", term.DotHere) 90 91 evals(f.Evaler, `pwclose $pipe`) 92 f.TestTTY(t, "> ", term.DotHere) 93 evals(f.Evaler, `prclose $pipe`) 94 } 95 96 func TestPromptStaleTransform(t *testing.T) { 97 f := setup(rc( 98 `pipe = (pipe)`, 99 `edit:prompt = { nop (slurp < $pipe); put '> ' }`, 100 `edit:prompt-stale-threshold = `+scaledMsAsSec(50), 101 `edit:prompt-stale-transform = [a]{ put S; put $a; put S }`)) 102 defer f.Cleanup() 103 104 f.TestTTY(t, "S???> S", term.DotHere) 105 evals(f.Evaler, `pwclose $pipe`) 106 evals(f.Evaler, `prclose $pipe`) 107 } 108 109 func TestPromptStaleTransform_Exception(t *testing.T) { 110 f := setup(rc( 111 `pipe = (pipe)`, 112 `edit:prompt = { nop (slurp < $pipe); put '> ' }`, 113 `edit:prompt-stale-threshold = `+scaledMsAsSec(50), 114 `edit:prompt-stale-transform = [_]{ fail ERROR }`)) 115 defer f.Cleanup() 116 117 f.TestTTYNotes(t, 118 "[prompt stale transform error] ERROR\n", 119 `see stack trace with "show $edit:exceptions[0]"`) 120 evals(f.Evaler, `excs = (count $edit:exceptions)`) 121 testGlobal(t, f.Evaler, "excs", "1") 122 } 123 124 func TestRPromptPersistent_True(t *testing.T) { 125 testRPromptPersistent(t, `edit:rprompt-persistent = $true`, 126 "~> "+strings.Repeat(" ", clitest.FakeTTYWidth-6)+"RRR", 127 "\n", term.DotHere, 128 ) 129 } 130 131 func TestRPromptPersistent_False(t *testing.T) { 132 testRPromptPersistent(t, `edit:rprompt-persistent = $false`, 133 "~> ", // no rprompt 134 "\n", term.DotHere, 135 ) 136 } 137 138 func testRPromptPersistent(t *testing.T, code string, finalBuf ...interface{}) { 139 f := setup(rc(`edit:rprompt = { put RRR }`, code)) 140 defer f.Cleanup() 141 142 // Make sure that the UI has stabilized before hitting Enter. 143 f.TestTTY(t, 144 "~> ", term.DotHere, 145 strings.Repeat(" ", clitest.FakeTTYWidth-6), "RRR", 146 ) 147 148 f.TTYCtrl.Inject(term.K('\n')) 149 f.TestTTY(t, finalBuf...) 150 } 151 152 func TestDefaultPromptForNonRoot(t *testing.T) { 153 f := setup(assign("edit:prompt", getDefaultPrompt(false))) 154 defer f.Cleanup() 155 156 f.TestTTY(t, "~> ", term.DotHere) 157 } 158 159 func TestDefaultPromptForRoot(t *testing.T) { 160 f := setup(assign("edit:prompt", getDefaultPrompt(true))) 161 defer f.Cleanup() 162 163 f.TestTTY(t, 164 "~# ", Styles, 165 " !!", term.DotHere) 166 } 167 168 func TestDefaultRPrompt(t *testing.T) { 169 f := setup(assign("edit:rprompt", getDefaultRPrompt("elf", "host"))) 170 defer f.Cleanup() 171 172 f.TestTTY(t, 173 "~> ", term.DotHere, strings.Repeat(" ", 39), 174 "elf@host", Styles, 175 "++++++++") 176 } 177 178 func scaledMsAsSec(ms int) string { 179 return fmt.Sprint(testutil.ScaledMs(ms).Seconds()) 180 }