119 lines
3.3 KiB
Go
119 lines
3.3 KiB
Go
//go:build windows
|
|
|
|
package win32_test
|
|
|
|
import (
|
|
"image"
|
|
"image/png"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"viewsagent/internal/capture"
|
|
"viewsagent/internal/win32"
|
|
)
|
|
|
|
// TestFrameVisibleButNotCaptured 验证取景框的两个关键性质:
|
|
// 1. 它确实显示在屏幕上(截屏能看到红框);
|
|
// 2. 打开"排除截屏"后,它不会被抓屏录进去(模型看到的画面里没有红框)。
|
|
//
|
|
// 这是个需要桌面会话的集成测试,默认跳过:
|
|
//
|
|
// VIEWSAGENT_UI_TEST=1 go test ./internal/win32/ -run Frame
|
|
func TestFrameVisibleButNotCaptured(t *testing.T) {
|
|
if os.Getenv("VIEWSAGENT_UI_TEST") == "" {
|
|
t.Skip("需要桌面会话,设置 VIEWSAGENT_UI_TEST=1 后运行")
|
|
}
|
|
|
|
f, err := win32.NewFrame()
|
|
if err != nil {
|
|
t.Skipf("无法创建取景框窗口(可能没有桌面会话): %v", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
region := capture.Region{X: 120, Y: 120, W: 420, H: 300}
|
|
f.SetRegion(win32.Rect{
|
|
Left: region.X, Top: region.Y,
|
|
Right: region.X + region.W, Bottom: region.Y + region.H,
|
|
})
|
|
time.Sleep(400 * time.Millisecond)
|
|
|
|
// 关闭排除:截屏里应该能看到红框,说明它真的贴在屏幕上。
|
|
f.SetCaptureExclusion(false)
|
|
time.Sleep(300 * time.Millisecond)
|
|
visible := grabRegion(t, region)
|
|
saveShot(t, "frame-visible.png", visible)
|
|
if n := countRedInBorder(visible, 3); n == 0 {
|
|
t.Fatal("取景框没有出现在屏幕上:关掉排除后截屏里也找不到红线")
|
|
} else {
|
|
t.Logf("边框窄带里有 %d 个红像素,取景框已显示在屏幕上", n)
|
|
}
|
|
|
|
// 打开排除:截屏里不应再有红线。
|
|
f.SetCaptureExclusion(true)
|
|
time.Sleep(300 * time.Millisecond)
|
|
hidden := grabRegion(t, region)
|
|
saveShot(t, "frame-excluded.png", hidden)
|
|
if n := countRedInBorder(hidden, 3); n != 0 {
|
|
t.Fatalf("取景框被录进截屏了,边框窄带里有 %d 个红像素", n)
|
|
}
|
|
t.Log("取景框已被排除在截屏之外")
|
|
}
|
|
|
|
// grabRegion 抓取一块屏幕区域。
|
|
func grabRegion(t *testing.T, r capture.Region) image.Image {
|
|
t.Helper()
|
|
img, err := (capture.Screen{}).Grab(r)
|
|
if err != nil {
|
|
t.Fatalf("抓屏失败: %v", err)
|
|
}
|
|
return img
|
|
}
|
|
|
|
// countRedInBorder 只统计区域四边 band 像素宽的窄带里的红色像素。
|
|
// 取景框只画在这一圈上,这样不会把页面里本来就有的红色(图标之类)算进来。
|
|
func countRedInBorder(img image.Image, band int) int {
|
|
b := img.Bounds()
|
|
isRed := func(x, y int) bool {
|
|
r, g, bl, _ := img.At(x, y).RGBA()
|
|
return r > 0xB000 && g < 0x5000 && bl < 0x5000
|
|
}
|
|
n := 0
|
|
for y := b.Min.Y; y < b.Max.Y; y++ {
|
|
for x := b.Min.X; x < b.Max.X; x++ {
|
|
nearEdge := x < b.Min.X+band || x >= b.Max.X-band ||
|
|
y < b.Min.Y+band || y >= b.Max.Y-band
|
|
if nearEdge && isRed(x, y) {
|
|
n++
|
|
}
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// saveShot 把截图写到 VIEWSAGENT_FRAME_SHOT_DIR 指定的目录,方便肉眼核对。
|
|
func saveShot(t *testing.T, name string, img image.Image) {
|
|
t.Helper()
|
|
dir := os.Getenv("VIEWSAGENT_FRAME_SHOT_DIR")
|
|
if dir == "" {
|
|
return
|
|
}
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
t.Logf("创建截图目录失败: %v", err)
|
|
return
|
|
}
|
|
path := filepath.Join(dir, name)
|
|
f, err := os.Create(path)
|
|
if err != nil {
|
|
t.Logf("创建截图文件失败: %v", err)
|
|
return
|
|
}
|
|
defer f.Close()
|
|
if err := png.Encode(f, img); err != nil {
|
|
t.Logf("写入截图失败: %v", err)
|
|
return
|
|
}
|
|
t.Logf("截图已保存: %s", path)
|
|
}
|