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