package braille import ( "bytes" "reflect" "testing" ) func TestDisplayMasksPreserveEveryRawCell(t *testing.T) { text := make([]rune, 256) dots := make([]byte, 256) for index := range text { text[index] = rune(0x2800 + index) dots[index] = 0x40 } andMask, orMask, err := displayMasks(string(text), nil) if err != nil { t.Fatal(err) } for index := range text { if andMask[index] != 0 || orMask[index] != byte(index) { t.Fatalf("cell %d: and=%x or=%x", index, andMask[index], orMask[index]) } } andMask, orMask, err = displayMasks(string(text), dots) if err != nil { t.Fatal(err) } for index := range text { if andMask[index] != 0 || orMask[index] != byte(index)|0x40 { t.Fatalf("cell %d lost raw dots or attributes", index) } } } func TestDisplayMasksRetainTextTranslation(t *testing.T) { andMask, orMask, err := displayMasks("a界 ⠁", []byte{0x40, 0, 0, 0x80}) if err != nil { t.Fatal(err) } if !bytes.Equal(andMask, []byte{0xff, 0xff, 0xff, 0}) || !bytes.Equal(orMask, []byte{0x40, 0, 0, 0x81}) { t.Fatalf("and=%x or=%x", andMask, orMask) } for _, tc := range []struct { text string dots []byte }{{"\xff", nil}, {"界", []byte{1, 2}}, {"", []byte{1}}} { if _, _, err := displayMasks(tc.text, tc.dots); err == nil { t.Fatal("accepted invalid frame") } } } func TestRawCellsCursorPaddingAndSnapshotOwnership(t *testing.T) { v := viewport{width: 4} if err := v.setFrame(Frame{ID: 8, Text: "⠁⠃", Cursor: 2, Dots: []byte{0x40, 0}}); err != nil { t.Fatal(err) } cells, err := v.rawCells(0xc0) if err != nil || !bytes.Equal(cells, []byte{0x41, 3, 0xc0, 0}) { t.Fatalf("cells=%x error=%v", cells, err) } if route, ok := v.route(RouteBase + 2); !ok || route != (RoutingEvent{ID: 8, Offset: 2}) { t.Fatalf("end-of-line route=%+v ok=%v", route, ok) } if _, ok := v.route(RouteBase + 3); ok { t.Fatal("padding has a routing target") } cells[0] = 0xff withoutCursor, err := v.rawCells(0) if err != nil || !bytes.Equal(withoutCursor, []byte{0x41, 3, 0, 0}) { t.Fatalf("snapshot or cursor mutated viewport: %x, %v", withoutCursor, err) } if err := v.setFrame(Frame{ID: 9, Cursor: -1}); err != nil { t.Fatal(err) } cleared, err := v.rawCells(0xc0) if err != nil || !bytes.Equal(cleared, make([]byte, 4)) { t.Fatalf("empty replacement=%x, %v", cleared, err) } if _, ok := v.route(RouteBase); ok { t.Fatal("empty replacement retained routing") } if cells[1] != 3 { t.Fatal("replacement changed an earlier snapshot") } } func TestRawCellsRequireTranslationAndValidWidth(t *testing.T) { v := viewport{width: 4} if err := v.setFrame(Frame{Text: "cat", Cursor: -1}); err != nil { t.Fatal(err) } if _, err := v.rawCells(0xc0); err == nil { t.Fatal("ordinary text was exported as guessed dots") } for _, width := range []int{-1, 0, 4097} { invalid := viewport{width: width} if _, err := invalid.rawCells(0); err == nil { t.Fatalf("accepted width %d", width) } } v = viewport{width: 4096} if err := v.setFrame(Frame{Cursor: -1}); err != nil { t.Fatal(err) } cells, err := v.rawCells(0) if err != nil || len(cells) != 4096 { t.Fatalf("maximum width: %d, %v", len(cells), err) } } func TestRawCellsFailureDoesNotAlterViewport(t *testing.T) { v := viewport{width: 2} if err := v.setFrame(Frame{Text: "abcd", Cursor: -1}); err != nil { t.Fatal(err) } v.pan(PanRight) before := v if _, err := v.rawCells(0xc0); err == nil { t.Fatal("accepted untranslated text") } if !reflect.DeepEqual(v, before) { t.Fatal("failed export changed local presentation") } }