cat / 012
clone

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

cat/module-path
012 / internal / ui / spans_test.go
spans_test.go 2.8K
1package ui23import (4 "encoding/json"5 "log/slog"6 "os"7 "path/filepath"8 "strings"9 "testing"10 "time"1112 "src.rest/cat/012/internal/sheet"13 "src.rest/cat/012/internal/telemetry"14)1516// logSpans turns telemetry on into a JSON log with the engine's hooks17// set as cmd/012 sets them, and returns what reads the events logged.18func logSpans(t *testing.T) func() []map[string]any {19 t.Helper()20 path := filepath.Join(t.TempDir(), "log.jsonl")21 stop, err := telemetry.Setup(telemetry.Config{LogPath: path})22 if err != nil {23 t.Fatal(err)24 }25 end := func(trace any, name string, d time.Duration, attrs ...slog.Attr) {26 if tr, ok := trace.(*telemetry.Trace); ok && tr.End(attrs...) {27 return28 }29 telemetry.Event(name, d, attrs...)30 }31 sheet.OnBegin = func(trace any, op string) {32 if tr, ok := trace.(*telemetry.Trace); ok {33 tr.Begin(op)34 }35 }36 sheet.OnRecalc = func(trace any, i sheet.RecalcInfo) { end(trace, "recalc", i.Duration) }37 sheet.OnPivot = func(trace any, i sheet.PivotInfo) { end(trace, "pivot", i.Duration) }38 t.Cleanup(func() {39 sheet.OnBegin, sheet.OnRecalc, sheet.OnPivot = nil, nil, nil40 stop()41 })42 return func() []map[string]any {43 stop()44 b, err := os.ReadFile(path)45 if err != nil {46 t.Fatal(err)47 }48 var evs []map[string]any49 for _, l := range strings.Split(strings.TrimSpace(string(b)), "\n") {50 var ev map[string]any51 if err := json.Unmarshal([]byte(l), &ev); err != nil {52 t.Fatal(err)53 }54 evs = append(evs, ev)55 }56 return evs57 }58}5960// under reports whether some event named child is logged under the one61// that matches parent.62func under(evs []map[string]any, child string, parent func(map[string]any) bool) bool {63 for _, p := range evs {64 if !parent(p) {65 continue66 }67 for _, c := range evs {68 if c["event"] == child && c["parent_id"] == p["span_id"] && c["trace_id"] == p["trace_id"] {69 return true70 }71 }72 }73 return false74}7576func spanNamed(event, id string) func(map[string]any) bool {77 return func(ev map[string]any) bool { return ev["event"] == event && (id == "" || ev["id"] == id) }78}7980// A trace shows what a command caused, and what a macro ran.81func TestSpansNest(t *testing.T) {82 read := logSpans(t)83 m := newModel()84 m.sheet.Set(addr("A1"), "1")85 m.sheet.Set(addr("B1"), "=A1*2")86 m.runCommand("clear")87 script(t, m, `88set("A2", 5)89run("format.bold")90`)91 evs := read()92 if !under(evs, "recalc", spanNamed("command", "clear")) {93 t.Error("clear's recalculation is not under its command")94 }95 if !under(evs, "command", spanNamed("macro", "")) {96 t.Error("the macro's command is not under the macro")97 }98 if !under(evs, "recalc", spanNamed("macro", "")) {99 t.Error("the macro's recalculation is not under the macro")100 }101 for _, ev := range evs {102 if ev["event"] == "command" && ev["id"] == "clear" && ev["parent_id"] != nil {103 t.Errorf("a command from a key is a root: %v", ev)104 }105 }106}