71 lines
1.7 KiB
Go
71 lines
1.7 KiB
Go
//go:build windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
func requireNativeGUI(t *testing.T) {
|
|
t.Helper()
|
|
if os.Getenv("AP_NATIVE_GUI") != "1" {
|
|
t.Skip("opt-in native GUI test; no process scanner is run")
|
|
}
|
|
}
|
|
func TestNativeTrayOneExitItemAndGracefulCommand(t *testing.T) {
|
|
requireNativeGUI(t)
|
|
requested := make(chan struct{})
|
|
restored := make(chan struct{})
|
|
close(restored)
|
|
var once sync.Once
|
|
tr, err := newTray(func() { once.Do(func() { close(requested) }) }, restored)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer tr.Close()
|
|
h := tr.hwnd.Load()
|
|
count, _, _ := u32.NewProc("GetMenuItemCount").Call(tr.menu)
|
|
if count != 1 {
|
|
t.Fatalf("want exactly one menu item, got %d", count)
|
|
}
|
|
var label [32]uint16
|
|
item := menuItemInfo{Size: uint32(unsafe.Sizeof(menuItemInfo{})), Mask: 0x40 | 0x2 | 0x80, Text: &label[0], TextLen: uint32(len(label))}
|
|
ok, _, e := u32.NewProc("GetMenuItemInfoW").Call(tr.menu, 0, 1, uintptr(unsafe.Pointer(&item)))
|
|
if ok == 0 {
|
|
t.Fatal(e)
|
|
}
|
|
if item.ID != menuExitID || item.Bitmap == 0 || string(utf16Runes(label[:])) != "Выход" {
|
|
t.Fatal("missing Exit label, command, or cross bitmap")
|
|
}
|
|
ok, _, e = pPostMessage.Call(h, 0x111, menuExitID, 0)
|
|
if ok == 0 {
|
|
t.Fatal(e)
|
|
}
|
|
select {
|
|
case <-requested:
|
|
case <-time.After(3 * time.Second):
|
|
t.Fatal("Exit command did not request graceful shutdown")
|
|
}
|
|
if err = tr.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
valid, _, _ := u32.NewProc("IsWindow").Call(h)
|
|
if valid != 0 {
|
|
t.Fatal("tray window leaked")
|
|
}
|
|
}
|
|
func utf16Runes(in []uint16) []rune {
|
|
out := []rune{}
|
|
for _, v := range in {
|
|
if v == 0 {
|
|
break
|
|
}
|
|
out = append(out, rune(v))
|
|
}
|
|
return out
|
|
}
|