Fenrir's emoji ported to cthulhu.
This commit is contained in:
1 parent
3e2429b8a5
commit
01f50c17e8
24 files changed
+1505
-9
No files matched your search
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/input"
|
||||
"git.stormux.org/storm/cthulhu/internal/interaction"
|
||||
)
|
||||
|
||||
type emojiTestSource struct {
|
||||
keys *uiTestKeys
|
||||
calls chan string
|
||||
err error
|
||||
}
|
||||
|
||||
func (source *emojiTestSource) TypeText(_ context.Context, text string) error {
|
||||
if source.keys.InternalUISession() != 0 {
|
||||
source.calls <- "capture retained"
|
||||
} else {
|
||||
source.calls <- text
|
||||
}
|
||||
return source.err
|
||||
}
|
||||
func TestEmojiHostCancelCheckboxMemoryAndClipboard(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
keys := &uiTestKeys{}
|
||||
source := &emojiTestSource{keys: keys, calls: make(chan string, 4)}
|
||||
copier := &ocrTestCopier{copied: make(chan string, 4)}
|
||||
output := &ocrTestOutput{speech: make(chan speechRequest, 64)}
|
||||
ui := &internalUI{keys: keys, emojiSource: source, emojiCopier: copier, speech: output, gate: &focusGate{}, events: make(chan input.CommandEvent, 32), done: make(chan struct{})}
|
||||
go ui.run(ctx)
|
||||
defer func() { cancel(); <-ui.done }()
|
||||
wait := func(prefix string) {
|
||||
t.Helper()
|
||||
for {
|
||||
select {
|
||||
case message := <-output.speech:
|
||||
if len(message.Text) >= len(prefix) && message.Text[:len(prefix)] == prefix {
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("missing %q", prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
open := func() {
|
||||
t.Helper()
|
||||
ui.Handle(input.CommandEvent{Command: input.EmojiMenu})
|
||||
wait("Emoji Menu. All tab")
|
||||
}
|
||||
key := func(symbol uint32, text string) {
|
||||
ui.Handle(input.CommandEvent{Command: input.InternalUIKey, UISession: 1, Chord: input.CommandChord{Symbol: symbol}, Text: text})
|
||||
}
|
||||
open()
|
||||
key(0xff09, "")
|
||||
key(0, "goat")
|
||||
key(0xff0d, "")
|
||||
wait("Inserted Goat")
|
||||
if got := <-source.calls; got != "🐐" {
|
||||
t.Fatal(got)
|
||||
}
|
||||
select {
|
||||
case got := <-copier.copied:
|
||||
t.Fatalf("default copied: %q", got)
|
||||
default:
|
||||
}
|
||||
|
||||
// Toggle copying on, cancel, and verify the next invocation retains the choice.
|
||||
open()
|
||||
key(0xff09, "")
|
||||
key(0xff09, "")
|
||||
key(0, " ")
|
||||
key(0xff1b, "")
|
||||
for keys.InternalUISession() != 0 {
|
||||
if ctx.Err() != nil {
|
||||
t.Fatal("cancel not processed")
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
open()
|
||||
key(0xff09, "")
|
||||
key(0, "astronaut")
|
||||
key(0xff0d, "")
|
||||
wait("Copied Astronaut to clipboard")
|
||||
if got := <-copier.copied; got != "🧑🚀" {
|
||||
t.Fatal(got)
|
||||
}
|
||||
select {
|
||||
case got := <-source.calls:
|
||||
t.Fatalf("copy mode typed: %q", got)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmojiTypingFailure(t *testing.T) {
|
||||
source := &emojiTestSource{keys: &uiTestKeys{}, calls: make(chan string, 1), err: errors.New("unsupported")}
|
||||
output := &ocrTestOutput{speech: make(chan speechRequest, 1)}
|
||||
ui := &internalUI{keys: source.keys, emojiSource: source, speech: output, gate: &focusGate{}}
|
||||
ui.select_emoji(context.Background(), interaction.Value{Selected: "🐐", Text: "Goat"}, false)
|
||||
if got := (<-output.speech).Text; got != "Emoji insertion unavailable" {
|
||||
t.Fatal(got)
|
||||
}
|
||||
}
|
||||
|
||||
type emojiBrowseKeys struct{ uiTestKeys }
|
||||
|
||||
func (*emojiBrowseKeys) BrowseNavigationEnabled() bool { return true }
|
||||
func TestEmojiBrowseModeBlocksTypingAndAllowsCopy(t *testing.T) {
|
||||
keys := &emojiBrowseKeys{}
|
||||
source := &emojiTestSource{keys: &keys.uiTestKeys, calls: make(chan string, 1)}
|
||||
copier := &ocrTestCopier{copied: make(chan string, 1)}
|
||||
output := &ocrTestOutput{speech: make(chan speechRequest, 2)}
|
||||
ui := &internalUI{keys: keys, emojiSource: source, emojiCopier: copier, speech: output, gate: &focusGate{}}
|
||||
ui.select_emoji(context.Background(), interaction.Value{Selected: "🐐", Text: "Goat"}, false)
|
||||
if got := (<-output.speech).Text; got != "Emoji insertion unavailable in browse mode" {
|
||||
t.Fatal(got)
|
||||
}
|
||||
ui.select_emoji(context.Background(), interaction.Value{Selected: "🐐", Text: "Goat"}, true)
|
||||
if got := (<-output.speech).Text; got != "Copied Goat to clipboard" {
|
||||
t.Fatal(got)
|
||||
}
|
||||
select {
|
||||
case got := <-source.calls:
|
||||
t.Fatalf("typed in browse mode: %q", got)
|
||||
default:
|
||||
}
|
||||
if got := <-copier.copied; got != "🐐" {
|
||||
t.Fatal(got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user