// Fenrir console screen reader. // Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with // this program. If not, see . //go:build linux && cgo package console import ( "os" "syscall" "testing" "time" ) func TestInputWatcherReadinessRearmAndHotplug(t *testing.T) { watcher, err := newReadinessWatcher(syscall.EPOLLIN) if err != nil { t.Fatal(err) } defer watcher.close() for device := 0; device < 2; device++ { readEnd, writeEnd, err := os.Pipe() if err != nil { t.Fatal(err) } t.Cleanup(func() { readEnd.Close(); writeEnd.Close() }) if err := watcher.add(int(readEnd.Fd())); err != nil { t.Fatal(err) } for press := 0; press < 2; press++ { if _, err := writeEnd.Write([]byte{1}); err != nil { t.Fatal(err) } select { case err := <-watcher.events: if err != nil { t.Fatal(err) } case <-time.After(time.Second): t.Fatal("input did not wake epoll") } var data [1]byte if _, err := readEnd.Read(data[:]); err != nil { t.Fatal(err) } if err := watcher.arm(int(readEnd.Fd())); err != nil { t.Fatal(err) } } readEnd.Close() writeEnd.Close() } } func TestInputWatcherIdleShutdown(t *testing.T) { watcher, err := newReadinessWatcher(syscall.EPOLLIN) if err != nil { t.Fatal(err) } closed := make(chan error, 1) go func() { closed <- watcher.close() }() select { case err := <-closed: if err != nil { t.Fatal(err) } case <-time.After(time.Second): t.Fatal("idle watcher failed to wake on shutdown") } } func BenchmarkInputReadiness(b *testing.B) { watcher, err := newReadinessWatcher(syscall.EPOLLIN) if err != nil { b.Fatal(err) } defer watcher.close() readEnd, writeEnd, err := os.Pipe() if err != nil { b.Fatal(err) } defer readEnd.Close() defer writeEnd.Close() if err := watcher.add(int(readEnd.Fd())); err != nil { b.Fatal(err) } var data [1]byte for b.Loop() { if _, err := writeEnd.Write(data[:]); err != nil { b.Fatal(err) } if err := <-watcher.events; err != nil { b.Fatal(err) } if _, err := readEnd.Read(data[:]); err != nil { b.Fatal(err) } if err := watcher.arm(int(readEnd.Fd())); err != nil { b.Fatal(err) } } }