Files
mapsize/internal/tui/live_test.go
T
Andy Dixon df8b10c6dd Add Bubble Tea TUI with interactive treemap
Cell canvas renderer with frame cache and a perceptual 256-colour
quantizer; responsive geometry (large/medium/small/too-small);
squarified treemap with nested previews, LOD grouping, category
colouring and adaptive labels; spatial arrow navigation with stable
NodeID selection; zoom and breadcrumbs; modal system (info, help,
confirm, save); list, file-type, top-N, scan-info, duplicate and
comparison views; live search/filter; mouse support; move-to-trash.
2026-10-02 08:25:35 +01:00

72 lines
1.7 KiB
Go

package tui
import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/andydixon/mapsize/internal/inventory"
"github.com/andydixon/mapsize/internal/scan"
)
// TestLiveScanRendering renders, navigates, filters and resizes while the
// scanner mutates the inventory. Run with -race to verify the locking
// discipline.
func TestLiveScanRendering(t *testing.T) {
root := t.TempDir()
for i := range 30 {
d := filepath.Join(root, fmt.Sprintf("d%02d", i), "sub")
if err := os.MkdirAll(d, 0o755); err != nil {
t.Fatal(err)
}
for j := range 40 {
os.WriteFile(filepath.Join(d, fmt.Sprintf("f%d.log", j)), make([]byte, (i+1)*(j+1)*100), 0o644)
}
}
start := func(ctx context.Context) (*scan.Scanner, *inventory.Tree, error) {
s, err := scan.Start(ctx, root, scan.Options{Workers: 4, ChunkSize: 3})
if err != nil {
return nil, nil, err
}
return s, s.Tree, nil
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s, tr, err := start(ctx)
if err != nil {
t.Fatal(err)
}
m := newModel(Options{Start: start}, s, tr, cancel)
sizes := [][2]int{{120, 40}, {80, 24}, {200, 60}, {45, 12}}
deadline := time.After(20 * time.Second)
for i := 0; ; i++ {
send(m, size(sizes[i%len(sizes)][0], sizes[i%len(sizes)][1]), tickMsg(time.Now()))
send(m, key([]string{"right", "down", "left", "up"}[i%4]))
if i%5 == 0 {
send(m, key("tab"))
}
if i == 3 {
m.search.ed.set("ext = log")
m.queryChanged()
send(m, m.applyFilter()())
}
m.dirty = true
m.View()
select {
case <-s.Done():
send(m, scanDoneMsg{s})
m.View()
if m.scanning {
t.Fatal("scan should be finished")
}
return
case <-deadline:
t.Fatal("scan did not finish")
default:
}
}
}