mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-15 23:25:49 +01:00
* test(v3): add comprehensive unit tests for pkg/application Add 11 new test files to improve test coverage of the pkg/application package from 13.6% to 17.7%. New test files: - context_test.go: Context struct operations - services_test.go: Service management and lifecycle - parameter_test.go: Parameter and CallError types - dialogs_test.go: Dialog utilities and button methods - webview_window_options_test.go: Window options and constants - application_options_test.go: ChainMiddleware and app config - keys_test.go: Keyboard accelerator parsing - single_instance_test.go: Single instance management and encryption - menuitem_internal_test.go: Menu item internal functions - menu_internal_test.go: Menu internal functions - screenmanager_internal_test.go: Screen geometry and transformations The 40% target was not fully achievable because ~50% of the codebase is platform-specific code that can only be tested on respective platforms. Tests focus on pure Go logic, utility functions, and data structures that can be tested cross-platform. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit review comments - dialogs_test.go: improve ID recycling test to verify either recycled ID (id3 == id1) or new unique ID (id3 > id2) - keys_test.go: make accelerator String() tests platform-agnostic by checking suffix patterns rather than exact platform-specific strings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: normalize temp dir path for macOS compatibility in test os.TempDir() returns a trailing slash on macOS, causing path comparison to fail. Use filepath.Clean() to normalize both paths. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove REVIEW.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: simplify changelog entry 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
403 lines
8.1 KiB
Go
403 lines
8.1 KiB
Go
package application
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestNewMenu(t *testing.T) {
|
|
menu := NewMenu()
|
|
if menu == nil {
|
|
t.Fatal("NewMenu returned nil")
|
|
}
|
|
if menu.items != nil {
|
|
t.Error("items should be nil initially")
|
|
}
|
|
}
|
|
|
|
func TestMenu_Add(t *testing.T) {
|
|
menu := NewMenu()
|
|
|
|
item := menu.Add("Test Item")
|
|
if item == nil {
|
|
t.Fatal("Add returned nil")
|
|
}
|
|
if item.label != "Test Item" {
|
|
t.Errorf("label = %q, want %q", item.label, "Test Item")
|
|
}
|
|
if len(menu.items) != 1 {
|
|
t.Errorf("items count = %d, want 1", len(menu.items))
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_AddSeparator(t *testing.T) {
|
|
menu := NewMenu()
|
|
|
|
menu.AddSeparator()
|
|
if len(menu.items) != 1 {
|
|
t.Errorf("items count = %d, want 1", len(menu.items))
|
|
}
|
|
if menu.items[0].itemType != separator {
|
|
t.Error("item should be a separator")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_AddCheckbox(t *testing.T) {
|
|
menu := NewMenu()
|
|
|
|
item := menu.AddCheckbox("Check Me", true)
|
|
if item == nil {
|
|
t.Fatal("AddCheckbox returned nil")
|
|
}
|
|
if item.label != "Check Me" {
|
|
t.Errorf("label = %q, want %q", item.label, "Check Me")
|
|
}
|
|
if item.itemType != checkbox {
|
|
t.Error("item should be a checkbox")
|
|
}
|
|
if !item.checked {
|
|
t.Error("checkbox should be checked")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_AddRadio(t *testing.T) {
|
|
menu := NewMenu()
|
|
|
|
item := menu.AddRadio("Radio Option", false)
|
|
if item == nil {
|
|
t.Fatal("AddRadio returned nil")
|
|
}
|
|
if item.label != "Radio Option" {
|
|
t.Errorf("label = %q, want %q", item.label, "Radio Option")
|
|
}
|
|
if item.itemType != radio {
|
|
t.Error("item should be a radio")
|
|
}
|
|
if item.checked {
|
|
t.Error("radio should not be checked")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_AddSubmenu(t *testing.T) {
|
|
menu := NewMenu()
|
|
|
|
subMenu := menu.AddSubmenu("Submenu")
|
|
if subMenu == nil {
|
|
t.Fatal("AddSubmenu returned nil")
|
|
}
|
|
if len(menu.items) != 1 {
|
|
t.Errorf("items count = %d, want 1", len(menu.items))
|
|
}
|
|
if menu.items[0].itemType != submenu {
|
|
t.Error("item should be a submenu")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_SetLabel(t *testing.T) {
|
|
menu := NewMenu()
|
|
|
|
menu.SetLabel("My Menu")
|
|
if menu.label != "My Menu" {
|
|
t.Errorf("label = %q, want %q", menu.label, "My Menu")
|
|
}
|
|
}
|
|
|
|
func TestMenu_ItemAt(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.Add("Item 0")
|
|
menu.Add("Item 1")
|
|
menu.Add("Item 2")
|
|
|
|
item := menu.ItemAt(1)
|
|
if item == nil {
|
|
t.Fatal("ItemAt returned nil")
|
|
}
|
|
if item.label != "Item 1" {
|
|
t.Errorf("label = %q, want %q", item.label, "Item 1")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_ItemAt_OutOfBounds(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.Add("Item")
|
|
|
|
if menu.ItemAt(-1) != nil {
|
|
t.Error("ItemAt(-1) should return nil")
|
|
}
|
|
if menu.ItemAt(1) != nil {
|
|
t.Error("ItemAt(1) should return nil for single item menu")
|
|
}
|
|
if menu.ItemAt(100) != nil {
|
|
t.Error("ItemAt(100) should return nil")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_FindByLabel(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.Add("First")
|
|
menu.Add("Second")
|
|
menu.Add("Third")
|
|
|
|
found := menu.FindByLabel("Second")
|
|
if found == nil {
|
|
t.Fatal("FindByLabel returned nil")
|
|
}
|
|
if found.label != "Second" {
|
|
t.Errorf("label = %q, want %q", found.label, "Second")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_FindByLabel_NotFound(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.Add("First")
|
|
|
|
found := menu.FindByLabel("NonExistent")
|
|
if found != nil {
|
|
t.Error("FindByLabel should return nil for non-existent label")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_FindByLabel_InSubmenu(t *testing.T) {
|
|
menu := NewMenu()
|
|
submenu := menu.AddSubmenu("Submenu")
|
|
submenu.Add("Nested Item")
|
|
|
|
found := menu.FindByLabel("Nested Item")
|
|
if found == nil {
|
|
t.Fatal("FindByLabel should find item in submenu")
|
|
}
|
|
if found.label != "Nested Item" {
|
|
t.Errorf("label = %q, want %q", found.label, "Nested Item")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_RemoveMenuItem(t *testing.T) {
|
|
menu := NewMenu()
|
|
item1 := menu.Add("First")
|
|
item2 := menu.Add("Second")
|
|
menu.Add("Third")
|
|
|
|
menu.RemoveMenuItem(item2)
|
|
if len(menu.items) != 2 {
|
|
t.Errorf("items count = %d, want 2", len(menu.items))
|
|
}
|
|
if menu.FindByLabel("Second") != nil {
|
|
t.Error("Second item should be removed")
|
|
}
|
|
|
|
// Clean up
|
|
removeMenuItemByID(item1.id)
|
|
}
|
|
|
|
func TestMenu_Clear(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.Add("First")
|
|
menu.Add("Second")
|
|
menu.Add("Third")
|
|
|
|
menu.Clear()
|
|
if menu.items != nil {
|
|
t.Error("items should be nil after Clear")
|
|
}
|
|
}
|
|
|
|
func TestMenu_Append(t *testing.T) {
|
|
menu1 := NewMenu()
|
|
menu1.Add("Item 1")
|
|
|
|
menu2 := NewMenu()
|
|
menu2.Add("Item 2")
|
|
menu2.Add("Item 3")
|
|
|
|
menu1.Append(menu2)
|
|
if len(menu1.items) != 3 {
|
|
t.Errorf("items count = %d, want 3", len(menu1.items))
|
|
}
|
|
|
|
// Clean up
|
|
menu1.Destroy()
|
|
}
|
|
|
|
func TestMenu_Append_Nil(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.Add("Item")
|
|
|
|
menu.Append(nil)
|
|
if len(menu.items) != 1 {
|
|
t.Error("Append(nil) should not change menu")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_Prepend(t *testing.T) {
|
|
menu1 := NewMenu()
|
|
menu1.Add("Item 3")
|
|
|
|
menu2 := NewMenu()
|
|
menu2.Add("Item 1")
|
|
menu2.Add("Item 2")
|
|
|
|
menu1.Prepend(menu2)
|
|
if len(menu1.items) != 3 {
|
|
t.Errorf("items count = %d, want 3", len(menu1.items))
|
|
}
|
|
if menu1.items[0].label != "Item 1" {
|
|
t.Errorf("First item should be 'Item 1', got %q", menu1.items[0].label)
|
|
}
|
|
|
|
// Clean up
|
|
menu1.Destroy()
|
|
}
|
|
|
|
func TestMenu_Clone(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.SetLabel("Original Menu")
|
|
menu.Add("Item 1")
|
|
menu.Add("Item 2")
|
|
|
|
clone := menu.Clone()
|
|
if clone == menu {
|
|
t.Error("Clone should return different pointer")
|
|
}
|
|
if clone.label != menu.label {
|
|
t.Error("Clone should have same label")
|
|
}
|
|
if len(clone.items) != len(menu.items) {
|
|
t.Error("Clone should have same number of items")
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
clone.Destroy()
|
|
}
|
|
|
|
func TestNewMenuFromItems(t *testing.T) {
|
|
item1 := NewMenuItem("Item 1")
|
|
item2 := NewMenuItem("Item 2")
|
|
item3 := NewMenuItem("Item 3")
|
|
|
|
menu := NewMenuFromItems(item1, item2, item3)
|
|
if menu == nil {
|
|
t.Fatal("NewMenuFromItems returned nil")
|
|
}
|
|
if len(menu.items) != 3 {
|
|
t.Errorf("items count = %d, want 3", len(menu.items))
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestNewSubmenu(t *testing.T) {
|
|
items := NewMenu()
|
|
items.Add("Sub Item 1")
|
|
items.Add("Sub Item 2")
|
|
|
|
item := NewSubmenu("My Submenu", items)
|
|
if item == nil {
|
|
t.Fatal("NewSubmenu returned nil")
|
|
}
|
|
if item.label != "My Submenu" {
|
|
t.Errorf("label = %q, want %q", item.label, "My Submenu")
|
|
}
|
|
if item.submenu != items {
|
|
t.Error("submenu should be the provided menu")
|
|
}
|
|
|
|
// Clean up
|
|
removeMenuItemByID(item.id)
|
|
}
|
|
|
|
func TestMenu_ProcessRadioGroups(t *testing.T) {
|
|
menu := NewMenu()
|
|
|
|
// Add some non-radio items
|
|
menu.Add("Regular Item")
|
|
|
|
// Add a group of radio items
|
|
radio1 := menu.AddRadio("Radio 1", true)
|
|
radio2 := menu.AddRadio("Radio 2", false)
|
|
radio3 := menu.AddRadio("Radio 3", false)
|
|
|
|
// Add separator to end the group
|
|
menu.AddSeparator()
|
|
|
|
// Add another group
|
|
radio4 := menu.AddRadio("Radio A", true)
|
|
radio5 := menu.AddRadio("Radio B", false)
|
|
|
|
// Process radio groups
|
|
menu.processRadioGroups()
|
|
|
|
// First group should be linked
|
|
if len(radio1.radioGroupMembers) != 3 {
|
|
t.Errorf("First group should have 3 members, got %d", len(radio1.radioGroupMembers))
|
|
}
|
|
if len(radio2.radioGroupMembers) != 3 {
|
|
t.Errorf("radio2 should have 3 members, got %d", len(radio2.radioGroupMembers))
|
|
}
|
|
if len(radio3.radioGroupMembers) != 3 {
|
|
t.Errorf("radio3 should have 3 members, got %d", len(radio3.radioGroupMembers))
|
|
}
|
|
|
|
// Second group should be linked
|
|
if len(radio4.radioGroupMembers) != 2 {
|
|
t.Errorf("Second group should have 2 members, got %d", len(radio4.radioGroupMembers))
|
|
}
|
|
if len(radio5.radioGroupMembers) != 2 {
|
|
t.Errorf("radio5 should have 2 members, got %d", len(radio5.radioGroupMembers))
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|
|
|
|
func TestMenu_SetContextData(t *testing.T) {
|
|
menu := NewMenu()
|
|
menu.Add("Item 1")
|
|
menu.Add("Item 2")
|
|
|
|
data := &ContextMenuData{Data: "test-data"}
|
|
menu.setContextData(data)
|
|
|
|
// Verify data was set on items
|
|
for _, item := range menu.items {
|
|
if item.contextMenuData != data {
|
|
t.Error("Context data should be set on all items")
|
|
}
|
|
}
|
|
|
|
// Clean up
|
|
menu.Destroy()
|
|
}
|