91 lines
3.0 KiB
Go
91 lines
3.0 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package ocr
|
|
|
|
import (
|
|
"image"
|
|
"math"
|
|
"testing"
|
|
)
|
|
|
|
func TestTransformScreenRectangle(t *testing.T) {
|
|
transform := Transform{
|
|
ImageContent: image.Rect(10, 20, 310, 221),
|
|
ScreenBounds: image.Rect(-120, -50, -20, 50),
|
|
HasScreenMapping: true,
|
|
}
|
|
for _, test := range []struct {
|
|
name string
|
|
bounds, expected image.Rectangle
|
|
valid bool
|
|
}{
|
|
{"full", transform.ImageContent, transform.ScreenBounds, true},
|
|
{"independent axes", image.Rect(13, 22, 19, 26), image.Rect(-119, -50, -117, -47), true},
|
|
{"partial padding", image.Rect(0, 0, 13, 22), image.Rect(-120, -50, -119, -49), true},
|
|
{"only padding", image.Rect(0, 0, 10, 20), image.Rectangle{}, false},
|
|
{"empty", image.Rectangle{}, image.Rectangle{}, false},
|
|
{"beyond image", image.Rect(400, 400, 410, 410), image.Rectangle{}, false},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
got, valid := transform.ScreenRectangle(test.bounds)
|
|
if got != test.expected || valid != test.valid {
|
|
t.Fatalf("mapped %v, %v; want %v, %v", got, valid, test.expected, test.valid)
|
|
}
|
|
})
|
|
}
|
|
transform.HasScreenMapping = false
|
|
if _, valid := transform.ScreenRectangle(transform.ImageContent); valid {
|
|
t.Fatal("clipboard image acquired screen coordinates")
|
|
}
|
|
transform.HasScreenMapping = true
|
|
transform.ScreenBounds = image.Rect(math.MinInt32, 0, math.MinInt32+100, 100)
|
|
if _, valid := transform.ScreenRectangle(transform.ImageContent); valid {
|
|
t.Fatal("unknown native origin acquired coordinates")
|
|
}
|
|
transform.ScreenBounds = image.Rect(-math.MaxInt32, 0, math.MaxInt32, 100)
|
|
if _, valid := transform.ScreenRectangle(transform.ImageContent); valid {
|
|
t.Fatal("overflow-sized screen rectangle acquired coordinates")
|
|
}
|
|
}
|
|
|
|
func TestRuneOffsetsAndWordHitTesting(t *testing.T) {
|
|
result := Result{
|
|
Text: "é 中文\ne\u0301",
|
|
Words: []Word{
|
|
{Text: "é", Span: Span{0, 1}},
|
|
{Text: "中文", Span: Span{2, 4}},
|
|
{Text: "e\u0301", Span: Span{5, 7}},
|
|
},
|
|
}
|
|
for offset, want := range []int{0, 2, 3, 6, 9, 10, 11, 13} {
|
|
got, valid := result.ByteOffset(offset)
|
|
if !valid || got != want {
|
|
t.Fatalf("byte offset %d = %d, %v; want %d", offset, got, valid, want)
|
|
}
|
|
}
|
|
for _, offset := range []int{-1, 1, 4, 7, 8} {
|
|
if word, valid := result.WordAt(offset); valid {
|
|
t.Fatalf("separator/end offset %d chose %q", offset, word.Text)
|
|
}
|
|
}
|
|
for _, offset := range []int{0, 2, 3, 5, 6} {
|
|
if _, valid := result.WordAt(offset); !valid {
|
|
t.Fatalf("word offset %d missing", offset)
|
|
}
|
|
}
|
|
for _, offset := range []int{-1, 8} {
|
|
if _, valid := result.ByteOffset(offset); valid {
|
|
t.Fatalf("invalid rune offset %d accepted", offset)
|
|
}
|
|
}
|
|
if offset, valid := (Result{}).ByteOffset(0); offset != 0 || !valid {
|
|
t.Fatal("empty document lost its end position")
|
|
}
|
|
phrase := Result{Text: "a b", Words: []Word{{Text: "a b", Span: Span{0, 3}}}}
|
|
if _, valid := phrase.WordAt(1); valid {
|
|
t.Fatal("whitespace inside an engine word acquired an activation target")
|
|
}
|
|
}
|