⚡ Optimize hotkey service
This commit is contained in:
387
internal/services/hotkey_service_test.go
Normal file
387
internal/services/hotkey_service_test.go
Normal file
@@ -0,0 +1,387 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
"voidraft/internal/models"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/services/log"
|
||||
)
|
||||
|
||||
// TestHotkeyServiceCreation 测试服务创建
|
||||
func TestHotkeyServiceCreation(t *testing.T) {
|
||||
logger := log.New()
|
||||
configService := &ConfigService{} // Mock
|
||||
|
||||
service := NewHotkeyService(configService, logger)
|
||||
if service == nil {
|
||||
t.Fatal("Failed to create hotkey service")
|
||||
}
|
||||
|
||||
if service.logger == nil {
|
||||
t.Error("Logger should not be nil")
|
||||
}
|
||||
|
||||
if service.registered.Load() {
|
||||
t.Error("Service should not have registered hotkey initially")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHotkeyValidation 测试热键验证
|
||||
func TestHotkeyValidation(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
combo *models.HotkeyCombo
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
name: "Nil combo",
|
||||
combo: nil,
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "Empty key",
|
||||
combo: &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Key: "",
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "No modifiers",
|
||||
combo: &models.HotkeyCombo{
|
||||
Key: "A",
|
||||
},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
name: "Valid: Ctrl+A",
|
||||
combo: &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Key: "A",
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
name: "Valid: Ctrl+Shift+F1",
|
||||
combo: &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Shift: true,
|
||||
Key: "F1",
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
name: "Valid: Alt+Space",
|
||||
combo: &models.HotkeyCombo{
|
||||
Alt: true,
|
||||
Key: "Space",
|
||||
},
|
||||
valid: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := service.isValidHotkey(tt.combo)
|
||||
if result != tt.valid {
|
||||
t.Errorf("Expected valid=%v, got %v", tt.valid, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestHotkeyConversion 测试热键转换
|
||||
func TestHotkeyConversion(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
combo *models.HotkeyCombo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Valid letter key",
|
||||
combo: &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Key: "A",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Valid number key",
|
||||
combo: &models.HotkeyCombo{
|
||||
Shift: true,
|
||||
Key: "1",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Valid function key",
|
||||
combo: &models.HotkeyCombo{
|
||||
Alt: true,
|
||||
Key: "F5",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid key",
|
||||
combo: &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Key: "InvalidKey",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
key, mods, err := service.convertHotkey(tt.combo)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Error("Expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if key == 0 {
|
||||
t.Error("Key should not be 0")
|
||||
}
|
||||
|
||||
if len(mods) == 0 {
|
||||
t.Error("Should have at least one modifier")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestHotkeyRegisterUnregister 测试注册和注销
|
||||
func TestHotkeyRegisterUnregister(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
combo := &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Shift: true,
|
||||
Key: "F10",
|
||||
}
|
||||
|
||||
// 测试注册
|
||||
err := service.RegisterHotkey(combo)
|
||||
if err != nil {
|
||||
t.Logf("Register failed (may be expected in test environment): %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !service.IsRegistered() {
|
||||
t.Error("Service should be registered")
|
||||
}
|
||||
|
||||
// 验证当前热键
|
||||
current := service.GetCurrentHotkey()
|
||||
if current == nil {
|
||||
t.Error("Current hotkey should not be nil")
|
||||
}
|
||||
|
||||
if current.Key != combo.Key {
|
||||
t.Errorf("Expected key %s, got %s", combo.Key, current.Key)
|
||||
}
|
||||
|
||||
// 测试注销
|
||||
err = service.UnregisterHotkey()
|
||||
if err != nil {
|
||||
t.Fatalf("Unregister failed: %v", err)
|
||||
}
|
||||
|
||||
if service.IsRegistered() {
|
||||
t.Error("Service should not be registered after unregister")
|
||||
}
|
||||
|
||||
current = service.GetCurrentHotkey()
|
||||
if current != nil {
|
||||
t.Error("Current hotkey should be nil after unregister")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHotkeyUpdate 测试更新热键
|
||||
func TestHotkeyUpdate(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
combo1 := &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Key: "F11",
|
||||
}
|
||||
|
||||
// 启用热键
|
||||
err := service.UpdateHotkey(true, combo1)
|
||||
if err != nil {
|
||||
t.Logf("Update (enable) failed: %v", err)
|
||||
return
|
||||
}
|
||||
defer service.UnregisterHotkey()
|
||||
|
||||
if !service.IsRegistered() {
|
||||
t.Error("Should be registered after enable")
|
||||
}
|
||||
|
||||
// 禁用热键
|
||||
err = service.UpdateHotkey(false, combo1)
|
||||
if err != nil {
|
||||
t.Fatalf("Update (disable) failed: %v", err)
|
||||
}
|
||||
|
||||
if service.IsRegistered() {
|
||||
t.Error("Should not be registered after disable")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHotkeyDoubleRegister 测试重复注册
|
||||
func TestHotkeyDoubleRegister(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
combo := &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Alt: true,
|
||||
Key: "F12",
|
||||
}
|
||||
|
||||
err := service.RegisterHotkey(combo)
|
||||
if err != nil {
|
||||
t.Skip("First registration failed")
|
||||
}
|
||||
defer service.UnregisterHotkey()
|
||||
|
||||
// 第二次注册应该先取消第一次注册,然后重新注册
|
||||
combo2 := &models.HotkeyCombo{
|
||||
Shift: true,
|
||||
Key: "F12",
|
||||
}
|
||||
|
||||
err = service.RegisterHotkey(combo2)
|
||||
if err != nil {
|
||||
t.Logf("Second registration failed: %v", err)
|
||||
}
|
||||
|
||||
// 验证当前热键是新的
|
||||
current := service.GetCurrentHotkey()
|
||||
if current != nil && current.Shift != combo2.Shift {
|
||||
t.Error("Should have updated to new hotkey")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHotkeyConcurrentAccess 测试并发访问
|
||||
func TestHotkeyConcurrentAccess(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
combo := &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Key: "G",
|
||||
}
|
||||
|
||||
const goroutines = 10
|
||||
done := make(chan bool, goroutines)
|
||||
|
||||
// 并发读取
|
||||
for i := 0; i < goroutines; i++ {
|
||||
go func() {
|
||||
for j := 0; j < 100; j++ {
|
||||
_ = service.IsRegistered()
|
||||
_ = service.GetCurrentHotkey()
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
// 主协程进行注册/注销操作
|
||||
go func() {
|
||||
for i := 0; i < 5; i++ {
|
||||
service.RegisterHotkey(combo)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
service.UnregisterHotkey()
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// 等待所有 goroutine 完成
|
||||
for i := 0; i < goroutines; i++ {
|
||||
<-done
|
||||
}
|
||||
|
||||
t.Log("Concurrent access test completed without panics")
|
||||
}
|
||||
|
||||
// TestHotkeyServiceShutdown 测试服务关闭
|
||||
func TestHotkeyServiceShutdown(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
combo := &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Shift: true,
|
||||
Key: "H",
|
||||
}
|
||||
|
||||
err := service.RegisterHotkey(combo)
|
||||
if err != nil {
|
||||
t.Skip("Registration failed")
|
||||
}
|
||||
|
||||
// 测试 ServiceShutdown
|
||||
err = service.ServiceShutdown()
|
||||
if err != nil {
|
||||
t.Fatalf("ServiceShutdown failed: %v", err)
|
||||
}
|
||||
|
||||
if service.IsRegistered() {
|
||||
t.Error("Should not be registered after shutdown")
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkHotkeyRegistration 基准测试:热键注册
|
||||
func BenchmarkHotkeyRegistration(b *testing.B) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
combo := &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Key: "B",
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
service.RegisterHotkey(combo)
|
||||
service.UnregisterHotkey()
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkHotkeyConversion 基准测试:热键转换
|
||||
func BenchmarkHotkeyConversion(b *testing.B) {
|
||||
logger := log.New()
|
||||
service := NewHotkeyService(&ConfigService{}, logger)
|
||||
|
||||
combo := &models.HotkeyCombo{
|
||||
Ctrl: true,
|
||||
Shift: true,
|
||||
Alt: true,
|
||||
Key: "F5",
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
service.convertHotkey(combo)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user