mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 15:32:50 -05:00
core: mock wayland context for tests & add i18n guidance to CONTRIBUTING
This commit is contained in:
@@ -38,7 +38,7 @@ func CheckCapability() bool {
|
||||
return found
|
||||
}
|
||||
|
||||
func NewManager(display *wlclient.Display) (*Manager, error) {
|
||||
func NewManager(display wlclient.WaylandDisplay) (*Manager, error) {
|
||||
m := &Manager{
|
||||
display: display,
|
||||
ctx: display.Context(),
|
||||
|
||||
392
core/internal/server/extworkspace/manager_test.go
Normal file
392
core/internal/server/extworkspace/manager_test.go
Normal file
@@ -0,0 +1,392 @@
|
||||
package extworkspace
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient"
|
||||
)
|
||||
|
||||
func TestStateChanged_BothNil(t *testing.T) {
|
||||
assert.True(t, stateChanged(nil, nil))
|
||||
}
|
||||
|
||||
func TestStateChanged_OneNil(t *testing.T) {
|
||||
s := &State{Groups: []*WorkspaceGroup{}}
|
||||
assert.True(t, stateChanged(s, nil))
|
||||
assert.True(t, stateChanged(nil, s))
|
||||
}
|
||||
|
||||
func TestStateChanged_GroupCountDiffers(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{ID: "group-1"}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{}}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestStateChanged_GroupIDDiffers(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{}, Workspaces: []*Workspace{}}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{{ID: "group-2", Outputs: []string{}, Workspaces: []*Workspace{}}}}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestStateChanged_OutputCountDiffers(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}, Workspaces: []*Workspace{}}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{}, Workspaces: []*Workspace{}}}}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestStateChanged_OutputNameDiffers(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}, Workspaces: []*Workspace{}}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"HDMI-A-1"}, Workspaces: []*Workspace{}}}}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestStateChanged_WorkspaceCountDiffers(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{},
|
||||
Workspaces: []*Workspace{{ID: "1", Name: "ws1"}},
|
||||
}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{},
|
||||
Workspaces: []*Workspace{},
|
||||
}}}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestStateChanged_WorkspaceFieldsDiffer(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{},
|
||||
Workspaces: []*Workspace{{
|
||||
ID: "1", Name: "ws1", State: 0, Active: false, Urgent: false, Hidden: false,
|
||||
}},
|
||||
}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{},
|
||||
Workspaces: []*Workspace{{
|
||||
ID: "2", Name: "ws1", State: 0, Active: false, Urgent: false, Hidden: false,
|
||||
}},
|
||||
}}}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
|
||||
b.Groups[0].Workspaces[0].ID = "1"
|
||||
b.Groups[0].Workspaces[0].Name = "ws2"
|
||||
assert.True(t, stateChanged(a, b))
|
||||
|
||||
b.Groups[0].Workspaces[0].Name = "ws1"
|
||||
b.Groups[0].Workspaces[0].State = 1
|
||||
assert.True(t, stateChanged(a, b))
|
||||
|
||||
b.Groups[0].Workspaces[0].State = 0
|
||||
b.Groups[0].Workspaces[0].Active = true
|
||||
assert.True(t, stateChanged(a, b))
|
||||
|
||||
b.Groups[0].Workspaces[0].Active = false
|
||||
b.Groups[0].Workspaces[0].Urgent = true
|
||||
assert.True(t, stateChanged(a, b))
|
||||
|
||||
b.Groups[0].Workspaces[0].Urgent = false
|
||||
b.Groups[0].Workspaces[0].Hidden = true
|
||||
assert.True(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestStateChanged_WorkspaceCoordinatesDiffer(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{},
|
||||
Workspaces: []*Workspace{{
|
||||
ID: "1", Name: "ws1", Coordinates: []uint32{0, 0},
|
||||
}},
|
||||
}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{},
|
||||
Workspaces: []*Workspace{{
|
||||
ID: "1", Name: "ws1", Coordinates: []uint32{1, 0},
|
||||
}},
|
||||
}}}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
|
||||
b.Groups[0].Workspaces[0].Coordinates = []uint32{0}
|
||||
assert.True(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestStateChanged_Equal(t *testing.T) {
|
||||
a := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{"eDP-1", "HDMI-A-1"},
|
||||
Workspaces: []*Workspace{
|
||||
{ID: "1", Name: "ws1", Coordinates: []uint32{0, 0}, State: 1, Active: true},
|
||||
{ID: "2", Name: "ws2", Coordinates: []uint32{1, 0}, State: 0, Active: false},
|
||||
},
|
||||
}}}
|
||||
b := &State{Groups: []*WorkspaceGroup{{
|
||||
ID: "group-1",
|
||||
Outputs: []string{"eDP-1", "HDMI-A-1"},
|
||||
Workspaces: []*Workspace{
|
||||
{ID: "1", Name: "ws1", Coordinates: []uint32{0, 0}, State: 1, Active: true},
|
||||
{ID: "2", Name: "ws2", Coordinates: []uint32{1, 0}, State: 0, Active: false},
|
||||
},
|
||||
}}}
|
||||
assert.False(t, stateChanged(a, b))
|
||||
}
|
||||
|
||||
func TestManager_ConcurrentGetState(t *testing.T) {
|
||||
m := &Manager{
|
||||
state: &State{
|
||||
Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}}},
|
||||
},
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
const goroutines = 50
|
||||
const iterations = 100
|
||||
|
||||
for i := 0; i < goroutines/2; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < iterations; j++ {
|
||||
s := m.GetState()
|
||||
_ = s.Groups
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < goroutines/2; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
for j := 0; j < iterations; j++ {
|
||||
m.stateMutex.Lock()
|
||||
m.state = &State{
|
||||
Groups: []*WorkspaceGroup{{ID: "group-1", Outputs: []string{"eDP-1"}}},
|
||||
}
|
||||
m.stateMutex.Unlock()
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestManager_ConcurrentSubscriberAccess(t *testing.T) {
|
||||
m := &Manager{
|
||||
stopChan: make(chan struct{}),
|
||||
dirty: make(chan struct{}, 1),
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
const goroutines = 20
|
||||
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
subID := string(rune('a' + id))
|
||||
ch := m.Subscribe(subID)
|
||||
assert.NotNil(t, ch)
|
||||
time.Sleep(time.Millisecond)
|
||||
m.Unsubscribe(subID)
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestManager_SyncmapGroupsConcurrentAccess(t *testing.T) {
|
||||
m := &Manager{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
const goroutines = 30
|
||||
const iterations = 50
|
||||
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
key := uint32(id)
|
||||
|
||||
for j := 0; j < iterations; j++ {
|
||||
state := &workspaceGroupState{
|
||||
id: key,
|
||||
outputIDs: map[uint32]bool{1: true},
|
||||
workspaceIDs: []uint32{uint32(j)},
|
||||
}
|
||||
m.groups.Store(key, state)
|
||||
|
||||
if loaded, ok := m.groups.Load(key); ok {
|
||||
assert.Equal(t, key, loaded.id)
|
||||
}
|
||||
|
||||
m.groups.Range(func(k uint32, v *workspaceGroupState) bool {
|
||||
_ = v.id
|
||||
_ = v.outputIDs
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
m.groups.Delete(key)
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestManager_SyncmapWorkspacesConcurrentAccess(t *testing.T) {
|
||||
m := &Manager{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
const goroutines = 30
|
||||
const iterations = 50
|
||||
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
key := uint32(id)
|
||||
|
||||
for j := 0; j < iterations; j++ {
|
||||
state := &workspaceState{
|
||||
id: key,
|
||||
workspaceID: "ws-1",
|
||||
name: "workspace",
|
||||
state: uint32(j % 4),
|
||||
coordinates: []uint32{uint32(j), 0},
|
||||
}
|
||||
m.workspaces.Store(key, state)
|
||||
|
||||
if loaded, ok := m.workspaces.Load(key); ok {
|
||||
assert.Equal(t, key, loaded.id)
|
||||
}
|
||||
|
||||
m.workspaces.Range(func(k uint32, v *workspaceState) bool {
|
||||
_ = v.name
|
||||
_ = v.state
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
m.workspaces.Delete(key)
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestManager_SyncmapOutputNamesConcurrentAccess(t *testing.T) {
|
||||
m := &Manager{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
const goroutines = 30
|
||||
const iterations = 50
|
||||
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
key := uint32(id)
|
||||
|
||||
for j := 0; j < iterations; j++ {
|
||||
m.outputNames.Store(key, "eDP-1")
|
||||
|
||||
if loaded, ok := m.outputNames.Load(key); ok {
|
||||
assert.NotEmpty(t, loaded)
|
||||
}
|
||||
|
||||
m.outputNames.Range(func(k uint32, v string) bool {
|
||||
_ = v
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
m.outputNames.Delete(key)
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestManager_NotifySubscribersNonBlocking(t *testing.T) {
|
||||
m := &Manager{
|
||||
dirty: make(chan struct{}, 1),
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
m.notifySubscribers()
|
||||
}
|
||||
|
||||
assert.Len(t, m.dirty, 1)
|
||||
}
|
||||
|
||||
func TestManager_PostQueueFull(t *testing.T) {
|
||||
m := &Manager{
|
||||
cmdq: make(chan cmd, 2),
|
||||
stopChan: make(chan struct{}),
|
||||
}
|
||||
|
||||
m.post(func() {})
|
||||
m.post(func() {})
|
||||
m.post(func() {})
|
||||
m.post(func() {})
|
||||
|
||||
assert.Len(t, m.cmdq, 2)
|
||||
}
|
||||
|
||||
func TestManager_GetStateNilState(t *testing.T) {
|
||||
m := &Manager{}
|
||||
|
||||
s := m.GetState()
|
||||
assert.NotNil(t, s.Groups)
|
||||
assert.Empty(t, s.Groups)
|
||||
}
|
||||
|
||||
func TestWorkspace_Fields(t *testing.T) {
|
||||
ws := Workspace{
|
||||
ID: "ws-1",
|
||||
Name: "workspace 1",
|
||||
Coordinates: []uint32{0, 0},
|
||||
State: 1,
|
||||
Active: true,
|
||||
Urgent: false,
|
||||
Hidden: false,
|
||||
}
|
||||
|
||||
assert.Equal(t, "ws-1", ws.ID)
|
||||
assert.Equal(t, "workspace 1", ws.Name)
|
||||
assert.True(t, ws.Active)
|
||||
assert.False(t, ws.Urgent)
|
||||
assert.False(t, ws.Hidden)
|
||||
}
|
||||
|
||||
func TestWorkspaceGroup_Fields(t *testing.T) {
|
||||
group := WorkspaceGroup{
|
||||
ID: "group-1",
|
||||
Outputs: []string{"eDP-1", "HDMI-A-1"},
|
||||
Workspaces: []*Workspace{
|
||||
{ID: "ws-1", Name: "workspace 1"},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, "group-1", group.ID)
|
||||
assert.Len(t, group.Outputs, 2)
|
||||
assert.Len(t, group.Workspaces, 1)
|
||||
}
|
||||
|
||||
func TestNewManager_GetRegistryError(t *testing.T) {
|
||||
mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t)
|
||||
|
||||
mockDisplay.EXPECT().Context().Return(nil)
|
||||
mockDisplay.EXPECT().GetRegistry().Return(nil, errors.New("failed to get registry"))
|
||||
|
||||
_, err := NewManager(mockDisplay)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "failed to get registry")
|
||||
}
|
||||
@@ -33,7 +33,7 @@ type cmd struct {
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
display *wlclient.Display
|
||||
display wlclient.WaylandDisplay
|
||||
ctx *wlclient.Context
|
||||
registry *wlclient.Registry
|
||||
manager *ext_workspace.ExtWorkspaceManagerV1
|
||||
|
||||
Reference in New Issue
Block a user