cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

main
012 / internal / ui / nbstream_test.go
nbstream_test.go 3.5K
1package ui23import (4 "context"5 "io"6 "strings"7 "testing"89 "src.rest/cat/012/internal/nushell"10)1112// streamPolls are the stream polls commands returned in tests, which13// run doesn't follow on its own (see pumpStreams).14var streamPolls []nbStreamMsg1516// pumpStreams hands the model the stream polls waiting, and those they17// start, until a poll finds nothing new after one found rows.18func pumpStreams(m *Model) {19 rows := false20 for i := 0; i < 50 && len(streamPolls) > 0; i++ {21 msg := streamPolls[0]22 streamPolls = streamPolls[1:]23 send(m, msg)24 if msg.ok {25 rows = true26 } else if rows {27 return28 }29 }30}3132// streamNu prints each line sent on lines, as a stream's pipeline33// would, until lines is closed or the run is stopped.34type streamNu struct {35 lines chan string36 scripts chan string37}3839func newStreamNu() *streamNu {40 return &streamNu{lines: make(chan string), scripts: make(chan string, 8)}41}4243func (f *streamNu) Run(ctx context.Context, job nushell.Job, script string, stdout io.Writer) error {44 if len(job.IDE) > 0 || job.Command == "help commands | get name" {45 return nushell.ErrMissing46 }47 f.scripts <- script48 for {49 select {50 case <-ctx.Done():51 return ctx.Err()52 case l, ok := <-f.lines:53 if !ok {54 return nil55 }56 io.WriteString(stdout, l+"\n")57 }58 }59}6061// A cell run as a stream shows as live, its rows reaching its output62// and the sheet it was sent to as the pipeline prints them, and Stop63// ends it keeping them.64func TestNotebookStream(t *testing.T) {65 streamPolls = nil66 m, _ := notebookModel(t, nil)67 nu := newStreamNu()68 m.SetShellRunner(nu)69 write(t, m, "log = tail -f app.log | lines | parse '{level} {msg}'")70 press(t, m, "f")71 if len(m.nb.runs.streams) != 1 || !strings.Contains(screen(m), "● live, 0 rows") {72 t.Fatalf("not live:\n%s", screen(m))73 }74 if script := <-nu.scripts; !strings.Contains(script, "to nuon --raw | print") {75 t.Errorf("not run as a stream: %s", script)76 }77 // Send it to a new sheet while it runs.78 press(t, m, "G", "<enter>")79 logs := m.book().Lookup("log")80 if logs == nil {81 t.Fatalf("no sheet log: %q", m.note)82 }83 nb := m.sheet84 m.showSheet(m.book().Sheets()[0])8586 nu.lines <- "{level: info, msg: started}"87 pumpStreams(m)88 nu.lines <- "{level: warn, msg: slow}"89 pumpStreams(m)90 if got := logs.Value(addr("B3")).String(); got != "slow" {91 t.Errorf("B3 = %q", got)92 }93 if got := logs.Value(addr("A1")).String(); got != "level" {94 t.Errorf("A1 = %q", got)95 }96 st := m.cellState(nb, firstStream(m))97 if !st.Live || !st.Running || st.Rows != 2 {98 t.Errorf("state %+v", st)99 }100 run(m, m.runCommand("nb.stop"))101 if len(m.nb.runs.streams) != 0 {102 t.Fatal("still streaming after Stop")103 }104 m.showSheet(nb)105 c, _ := m.nbCell()106 o := m.book().Output(c.ID)107 if o == nil || o.Failed() || !strings.Contains(string(o.NUON), "slow") {108 t.Errorf("output after Stop: %+v", o)109 }110 if got := logs.Value(addr("B3")).String(); got != "slow" {111 t.Errorf("after Stop B3 = %q", got)112 }113 if strings.Contains(screen(m), "live") {114 t.Errorf("still shown live:\n%s", screen(m))115 }116}117118func firstStream(m *Model) int {119 for id := range m.nb.runs.streams {120 return id121 }122 return -1123}124125// A cell running as a stream reads without color: ● live and its rows126// in words, and ■ for ▶.127func TestMonochromeStream(t *testing.T) {128 streamPolls = nil129 m, _ := notebookModel(t, nil)130 nu := newStreamNu()131 m.SetShellRunner(nu)132 write(t, m, "tail -f app.log | lines")133 press(t, m, "f")134 defer m.stopCells()135 nu.lines <- `"started"`136 pumpStreams(m)137 findLine(t, m, "● live, 1 row")138 findLine(t, m, "■")139}