// 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") } }