//go:build brlapi && cgo // Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package braille import ( "bytes" "context" "encoding/json" "strings" "testing" ) func runVirtualLines(t *testing.T, lines ...string) []VirtualResponse { t.Helper() var output bytes.Buffer if err := RunVirtual(context.Background(), strings.NewReader(strings.Join(lines, "\n")+"\n"), &output); err != nil { t.Fatal(err) } var responses []VirtualResponse decoder := json.NewDecoder(&output) for decoder.More() { var response VirtualResponse if err := decoder.Decode(&response); err != nil { t.Fatal(err) } responses = append(responses, response) } return responses } func TestVirtualHelperRendersPansAndRoutes(t *testing.T) { responses := runVirtualLines(t, `{"frame":{"text":"abcdef","cursor":1,"id":9}}`, // No width yet: nothing rendered. `{"width":4}`, `{"pan":"right"}`, `{"route":1}`, `{"pan":"left"}`, `{"width":0}`, `{"frame":{"text":"x","cursor":-1,"id":10}}`, ) if len(responses) != 4 { t.Fatalf("responses = %+v", responses) } first := responses[0].Cells // Computer Braille a=dot1, b=dots12; the cursor on b adds dots 7 and 8. if len(first) != 4 || first[0] != 0x01 || first[1] != 0x03|VirtualCursorDots { t.Fatalf("first page = %#v", first) } if second := responses[1].Cells; len(second) != 4 || second[0] == first[0] { t.Fatalf("pan right did not change the page: %#v", second) } if route := responses[2].Route; route == nil || route.ID != 9 || route.Offset != 5 { t.Fatalf("route = %+v", route) } if !equalCells(responses[3].Cells, first) { t.Fatalf("pan left did not restore the first page: %#v", responses[3].Cells) } } func equalCells(a, b []int) bool { if len(a) != len(b) { return false } for index := range a { if a[index] != b[index] { return false } } return true } func TestVirtualHelperUsesContractedFrameTable(t *testing.T) { responses := runVirtualLines(t, `{"width":8}`, `{"frame":{"text":"the cat","cursor":-1,"id":1,"contract":true,"table":"en-ueb-g2.ctb"}}`) if len(responses) != 1 || len(responses[0].Cells) != 8 { t.Fatalf("responses = %+v", responses) } // Contraction makes "the" a single cell, so the line fits in fewer cells // than its seven characters: the last cell is blank padding. if responses[0].Cells[7] != 0 { t.Fatalf("contracted output was not shorter: %#v", responses[0].Cells) } } func TestVirtualHelperRejectsInvalidRequests(t *testing.T) { for _, line := range []string{`{"width":5000}`, `{}`, `not json`, `{"pan":"up"}`} { var output bytes.Buffer if RunVirtual(context.Background(), strings.NewReader(line+"\n"), &output) == nil { t.Fatal("invalid request accepted", line) } } }