package ui import ( "strings" "testing" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) func rowText(screen tcell.SimulationScreen, y, x0, x1 int) string { var b strings.Builder for x := x0; x < x1; x++ { ch, _, _, _ := screen.GetContent(x, y) b.WriteRune(ch) } return b.String() } func TestFlowWrap(t *testing.T) { text := "one two three four five six seven eight nine ten" // Narrow (10) for the first two lines, wide (25) afterwards. got := flowWrap(text, 10, 25, 2) want := []string{"one two", "three four", "five six seven eight nine", "ten"} if strings.Join(got, "|") != strings.Join(want, "|") { t.Errorf("got %q, want %q", got, want) } // Without a poster everything is wide. if got := flowWrap(text, 10, 25, 0); got[0] != "one two three four five" { t.Errorf("no poster: %q", got) } // Newlines are kept, blank lines too; trailing blank lines are dropped. got = flowWrap("head\nfacts\n\nplot words\n", 20, 20, 0) if strings.Join(got, "|") != "head|facts||plot words" { t.Errorf("newlines: %q", got) } // Color tags have no width and escaped brackets count as one character. got = flowWrap("[red]ab[-] cd ef", 5, 5, 0) if strings.Join(got, "|") != "[red]ab[-] cd|ef" { t.Errorf("tags: %q", got) } if got := flowWrap(tview.Escape("[1080p]")+" x", 9, 9, 0); len(got) != 1 { t.Errorf("escaped brackets: %q", got) } // A word wider than the column is not split or lost. if got := flowWrap("a verylongwordhere b", 5, 5, 0); strings.Join(got, "|") != "a|verylongwordhere|b" { t.Errorf("long word: %q", got) } } func TestDetailPaneFlowsAroundPoster(t *testing.T) { a := newTestApp(t) screen := tcell.NewSimulationScreen("") if err := screen.Init(); err != nil { t.Fatal(err) } defer screen.Fini() screen.SetSize(60, 40) plot := strings.Repeat("plot ", 220) // long enough to run past the poster d := newDetailPane(a) d.SetRect(0, 0, 60, 40) d.Show(detailText{head: "[::b]The Matrix (1999)[::-]\nStatus: released\n", plot: plot}, coverRef{}) // Without a poster the text uses the full width from the top. d.Draw(screen) if got := rowText(screen, 1, 1, 30); !strings.HasPrefix(got, "The Matrix (1999)") { t.Errorf("first line = %q", got) } if got := strings.TrimSpace(rowText(screen, 5, 1, 59)); len(got) < 50 { t.Errorf("without a poster the text should use the full width: %q", got) } // With a poster (23×17 cells at the top right) the text runs beside it. d.hasCover = true d.cover.setImage(stripes(40, 60)) d.Draw(screen) if d.coverW != 23 || d.coverH != 17 { t.Fatalf("poster size %dx%d, want 23x17", d.coverW, d.coverH) } if got := rowText(screen, 1, 1, 30); !strings.HasPrefix(got, "The Matrix (1999)") { t.Errorf("head moved: %q", got) } if got := rowText(screen, 4, 1, 30); !strings.HasPrefix(got, "plot plot") { t.Errorf("the plot starts beside the poster, right after the head: %q", got) } // Beside the poster the text stays left of it with a gap of two columns // (58-23-2 = 33 columns), and the row right under the poster is kept clear too. for y := 1; y <= d.coverH+coverGapRows; y++ { if got := strings.TrimRight(rowText(screen, y, 1, 36), " "); len([]rune(got)) > 33 { t.Errorf("row %d runs into the poster's margin: %q", y, got) } } // Further down it uses the full width. if got := strings.TrimSpace(rowText(screen, d.coverH+3, 1, 59)); len(got) < 50 { t.Errorf("below the poster the text should use the full width: %q", got) } // The poster sits against the right edge of the pane. if ch, _, st, _ := screen.GetContent(58, 1); ch == ' ' && st == tcell.StyleDefault { t.Error("nothing drawn at the poster's right edge") } // A pane too short for the poster falls back to plain text. d.SetRect(0, 0, 60, 10) d.Draw(screen) if d.coverW != 0 { t.Error("a short pane must drop the poster") } }