1package ui23import (4 "strings"5 "testing"67 "src.rest/cat/012/internal/sheet"8)910// Format > Alignment's Top, Middle and Bottom put a value on the first,11// middle or last line of a tall row, and wrapped text starts there.12func TestVerticalAlignment(t *testing.T) {13 m := newModel()14 press(t, m, "x", "<tab>", "one two three", "<enter>")15 m.sheet.SetRowHeight(0, 0, 5)16 m.cur = addr("A1")17 lineOf := func(text string) int {18 for i, l := range gridLines(m)[:5] {19 if strings.Contains(l, text) {20 return i21 }22 }23 return -124 }25 if got := lineOf("x"); got != 4 {26 t.Errorf("automatic: x on line %d", got)27 }28 for id, want := range map[string]int{"format.valign_top": 0, "format.valign_middle": 2, "format.valign_bottom": 4} {29 run(m, m.runCommand(id))30 if got := lineOf("x"); got != want || !commands[id].checked(m) {31 t.Errorf("%s: x on line %d, want %d", id, got, want)32 }33 }34 m.cur = addr("B1")35 run(m, m.runCommand("format.wrap"))36 run(m, m.runCommand("format.valign_middle"))37 if lineOf("one") != 1 || lineOf("three") != 2 {38 t.Errorf("wrapped in the middle:\n%s", strings.Join(gridLines(m)[:5], "\n"))39 }40 press(t, m, "<ctrl+z>")41 if lineOf("one") != 3 {42 t.Errorf("undo:\n%s", strings.Join(gridLines(m)[:5], "\n"))43 }44 if !menuHas(m, "Format", "Alignment") {45 t.Error("no Format > Alignment")46 }47}4849// menuHas reports whether the menu titled top has an item titled title.50func menuHas(m *Model, top, title string) bool {51 for _, mn := range menuBar {52 if mn.title != top {53 continue54 }55 for _, it := range mn.items {56 if it.label() == title {57 return true58 }59 }60 }61 return false62}6364// Border color picks the color the next borders draw in, which a65// recording keeps as the command's answer.66func TestBorderColor(t *testing.T) {67 m := newModel()68 press(t, m, "a", "<tab>", "b", "<enter>")69 run(m, m.runCommand("format.border_color"))70 press(t, m, "red", "<enter>")71 if m.borderColor != sheet.ColorRed || !strings.Contains(m.note, "red") {72 t.Fatalf("color %v, note %q", m.borderColor, m.note)73 }74 m.selectRect(rect("A1:B1"))75 run(m, m.runCommand("format.borders_outer"))76 if st := m.sheet.StrokeAbove(addr("A1")); st != (sheet.Stroke{Line: sheet.LineThin, Color: sheet.ColorRed}) {77 t.Errorf("top edge %+v", st)78 }79 if v := m.View().Content; !strings.Contains(v, m.th.RuleText[sheet.ColorRed].Render("│")) {80 t.Error("the lines aren't drawn red")81 }82 m = newModel()83 script(t, m, `run("format.border_color", answer="Blue")84run("format.borders_all")`)85 if st := m.sheet.StrokeLeft(addr("A1")); st.Color != sheet.ColorBlue {86 t.Errorf("script's border %+v, %q", st, m.warn)87 }88}8990// A double line meeting a thick outline ends in a thick tee whose arm91// runs on into the double line, as Unicode has no joint of the two.92func TestDoubleMeetsThick(t *testing.T) {93 m := newModel()94 press(t, m, "Day", "<tab>", "Cost", "<enter>", "Fri", "<tab>", "12", "<enter>")95 m.selectRect(rect("A1:B2"))96 run(m, m.runCommand("format.borders_all"))97 run(m, m.runCommand("format.border_thick"))98 run(m, m.runCommand("format.borders_outer"))99 m.selectRect(rect("A1:B1"))100 run(m, m.runCommand("format.border_double"))101 run(m, m.runCommand("format.border_bottom"))102 g := gridLines(m)103 if !strings.Contains(g[2], "┣━════════╪════════━┫") || strings.ContainsAny(g[2], "╠╣") {104 t.Errorf("joint under the headers: %q", g[2])105 }106}107108// Typing in a merged cell shows the entry as wide as the merge, and109// stepping off it goes on along the row or column it was entered by.110func TestMergeEntryAndMemory(t *testing.T) {111 m := newModel()112 m.selectRect(rect("B1:C3"))113 run(m, m.runCommand("format.merge_all"))114 m.clearSelection()115 m.cur = addr("B1")116 press(t, m, "a title wider than one column")117 if !strings.Contains(screen(m), "a title wider than one c") {118 t.Errorf("entry not as wide as the merge:\n%s", screen(m))119 }120 press(t, m, "<esc>")121 m.cur = addr("A2")122 press(t, m, "<right>")123 if m.cur != addr("B1") {124 t.Fatalf("into the merge: %v", m.cur)125 }126 press(t, m, "<right>")127 if m.cur != addr("D2") {128 t.Errorf("out of the merge along row 2: %v", m.cur)129 }130 m.cur = addr("C5")131 press(t, m, "<up>", "<up>", "<down>")132 if m.cur != addr("C4") {133 t.Errorf("down out of the merge along column C: %v", m.cur)134 }135 // Freezing through a merge is refused.136 m.cur = addr("B2")137 run(m, m.runCommand("view.freeze_rows2"))138 if m.mode != modeError || !strings.Contains(m.errMsg, "B1:C3") {139 t.Errorf("froze through a merge: %v %q", m.mode, m.errMsg)140 }141 if fr, _ := m.sheet.Frozen(); fr != 0 {142 t.Errorf("froze %d rows", fr)143 }144}145146// A merged cell's value sits on the middle one of the lines its rows147// take, rule lines between them included, whatever their heights; Top148// and Bottom put it on the first or last.149func TestMergeCenteredByLines(t *testing.T) {150 m := newModel()151 press(t, m, "mid", "<enter>")152 m.sheet.SetRowHeight(0, 0, 5)153 m.selectRect(rect("A1:A3"))154 run(m, m.runCommand("format.merge_vertical"))155 m.View()156 if row, k := m.mergeText(rect("A1:A3")); row != 0 || k != 3 {157 t.Errorf("middle of 7 lines at row %d line %d", row, k)158 }159 m.cur = addr("A1")160 m.clearSelection()161 run(m, m.runCommand("format.valign_bottom"))162 m.View()163 if row, k := m.mergeText(rect("A1:A3")); row != 2 || k != 0 {164 t.Errorf("bottom at row %d line %d", row, k)165 }166 if !strings.Contains(gridLines(m)[6], "mid") {167 t.Errorf("drawn:\n%s", strings.Join(gridLines(m)[:8], "\n"))168 }169}