mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 13:32:50 -05:00
core: mock wayland context for tests & add i18n guidance to CONTRIBUTING
This commit is contained in:
@@ -21,6 +21,7 @@ nix develop
|
|||||||
```
|
```
|
||||||
|
|
||||||
This will provide:
|
This will provide:
|
||||||
|
|
||||||
- Go 1.24 toolchain (go, gopls, delve, go-tools) and GNU Make
|
- Go 1.24 toolchain (go, gopls, delve, go-tools) and GNU Make
|
||||||
- Quickshell and required QML packages
|
- Quickshell and required QML packages
|
||||||
- Properly configured QML2_IMPORT_PATH
|
- Properly configured QML2_IMPORT_PATH
|
||||||
@@ -54,6 +55,20 @@ touch .qmlls.ini
|
|||||||
|
|
||||||
5. Make your changes, test, and open a pull request.
|
5. Make your changes, test, and open a pull request.
|
||||||
|
|
||||||
|
### I18n/Localization
|
||||||
|
|
||||||
|
When adding user-facing strings, ensure they are wrapped in `I18n.tr()` with context, for example.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: I18n.tr("Hello World", "<This is context for the translators, example> Hello world greeting that appears on the lock screen")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Preferably, try to keep new terms to a minimum and re-use existing terms where possible. See `quickshell/translations/en.json` for the list of existing terms. (This isn't always possible obviously, but instead of using `Auto-connect` you would use `Autoconnect` since it's already translated)
|
||||||
|
|
||||||
### GO (`core` directory)
|
### GO (`core` directory)
|
||||||
|
|
||||||
1. Install the [Go Extension](https://code.visualstudio.com/docs/languages/go)
|
1. Install the [Go Extension](https://code.visualstudio.com/docs/languages/go)
|
||||||
|
|||||||
@@ -56,3 +56,15 @@ packages:
|
|||||||
outpkg: mocks_version
|
outpkg: mocks_version
|
||||||
interfaces:
|
interfaces:
|
||||||
VersionFetcher:
|
VersionFetcher:
|
||||||
|
github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlcontext:
|
||||||
|
config:
|
||||||
|
dir: "internal/mocks/wlcontext"
|
||||||
|
outpkg: mocks_wlcontext
|
||||||
|
interfaces:
|
||||||
|
WaylandContext:
|
||||||
|
github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client:
|
||||||
|
config:
|
||||||
|
dir: "internal/mocks/wlclient"
|
||||||
|
outpkg: mocks_wlclient
|
||||||
|
interfaces:
|
||||||
|
WaylandDisplay:
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -281,10 +282,9 @@ func runCommand(args []string, stdin []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runClipHistory(cmd *cobra.Command, args []string) {
|
func runClipHistory(cmd *cobra.Command, args []string) {
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.getHistory",
|
Method: "clipboard.getHistory",
|
||||||
"params": map[string]any{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := sendServerRequest(req)
|
resp, err := sendServerRequest(req)
|
||||||
@@ -305,7 +305,7 @@ func runClipHistory(cmd *cobra.Command, args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
historyList, ok := resp.Result.([]any)
|
historyList, ok := (*resp.Result).([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("Invalid response format")
|
log.Fatal("Invalid response format")
|
||||||
}
|
}
|
||||||
@@ -353,10 +353,10 @@ func runClipGet(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if clipGetCopy {
|
if clipGetCopy {
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.copyEntry",
|
Method: "clipboard.copyEntry",
|
||||||
"params": map[string]any{
|
Params: map[string]any{
|
||||||
"id": id,
|
"id": id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -374,10 +374,10 @@ func runClipGet(cmd *cobra.Command, args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.getEntry",
|
Method: "clipboard.getEntry",
|
||||||
"params": map[string]any{
|
Params: map[string]any{
|
||||||
"id": id,
|
"id": id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -395,7 +395,7 @@ func runClipGet(cmd *cobra.Command, args []string) {
|
|||||||
log.Fatal("Entry not found")
|
log.Fatal("Entry not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
entry, ok := resp.Result.(map[string]any)
|
entry, ok := (*resp.Result).(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("Invalid response format")
|
log.Fatal("Invalid response format")
|
||||||
}
|
}
|
||||||
@@ -420,10 +420,10 @@ func runClipDelete(cmd *cobra.Command, args []string) {
|
|||||||
log.Fatalf("Invalid ID: %v", err)
|
log.Fatalf("Invalid ID: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.deleteEntry",
|
Method: "clipboard.deleteEntry",
|
||||||
"params": map[string]any{
|
Params: map[string]any{
|
||||||
"id": id,
|
"id": id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -441,10 +441,9 @@ func runClipDelete(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runClipClear(cmd *cobra.Command, args []string) {
|
func runClipClear(cmd *cobra.Command, args []string) {
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.clearHistory",
|
Method: "clipboard.clearHistory",
|
||||||
"params": map[string]any{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := sendServerRequest(req)
|
resp, err := sendServerRequest(req)
|
||||||
@@ -477,10 +476,10 @@ func runClipSearch(cmd *cobra.Command, args []string) {
|
|||||||
params["isImage"] = false
|
params["isImage"] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.search",
|
Method: "clipboard.search",
|
||||||
"params": params,
|
Params: params,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := sendServerRequest(req)
|
resp, err := sendServerRequest(req)
|
||||||
@@ -492,7 +491,11 @@ func runClipSearch(cmd *cobra.Command, args []string) {
|
|||||||
log.Fatalf("Error: %s", resp.Error)
|
log.Fatalf("Error: %s", resp.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, ok := resp.Result.(map[string]any)
|
if resp.Result == nil {
|
||||||
|
log.Fatal("No results")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok := (*resp.Result).(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("Invalid response format")
|
log.Fatal("Invalid response format")
|
||||||
}
|
}
|
||||||
@@ -540,10 +543,9 @@ func runClipSearch(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runClipConfigGet(cmd *cobra.Command, args []string) {
|
func runClipConfigGet(cmd *cobra.Command, args []string) {
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.getConfig",
|
Method: "clipboard.getConfig",
|
||||||
"params": map[string]any{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := sendServerRequest(req)
|
resp, err := sendServerRequest(req)
|
||||||
@@ -555,7 +557,11 @@ func runClipConfigGet(cmd *cobra.Command, args []string) {
|
|||||||
log.Fatalf("Error: %s", resp.Error)
|
log.Fatalf("Error: %s", resp.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, ok := resp.Result.(map[string]any)
|
if resp.Result == nil {
|
||||||
|
log.Fatal("No config returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, ok := (*resp.Result).(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatal("Invalid response format")
|
log.Fatal("Invalid response format")
|
||||||
}
|
}
|
||||||
@@ -603,10 +609,10 @@ func runClipConfigSet(cmd *cobra.Command, args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req := map[string]any{
|
req := models.Request{
|
||||||
"id": 1,
|
ID: 1,
|
||||||
"method": "clipboard.setConfig",
|
Method: "clipboard.setConfig",
|
||||||
"params": params,
|
Params: params,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := sendServerRequest(req)
|
resp, err := sendServerRequest(req)
|
||||||
|
|||||||
@@ -2,15 +2,12 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/matugen"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/matugen"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -100,33 +97,10 @@ func runMatugenQueue(cmd *cobra.Command, args []string) {
|
|||||||
wait, _ := cmd.Flags().GetBool("wait")
|
wait, _ := cmd.Flags().GetBool("wait")
|
||||||
timeout, _ := cmd.Flags().GetDuration("timeout")
|
timeout, _ := cmd.Flags().GetDuration("timeout")
|
||||||
|
|
||||||
socketPath := os.Getenv("DMS_SOCKET")
|
request := models.Request{
|
||||||
if socketPath == "" {
|
ID: 1,
|
||||||
var err error
|
Method: "matugen.queue",
|
||||||
socketPath, err = server.FindSocket()
|
Params: map[string]any{
|
||||||
if err != nil {
|
|
||||||
log.Info("No socket available, running synchronously")
|
|
||||||
if err := matugen.Run(opts); err != nil {
|
|
||||||
log.Fatalf("Theme generation failed: %v", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := net.Dial("unix", socketPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Info("Socket connection failed, running synchronously")
|
|
||||||
if err := matugen.Run(opts); err != nil {
|
|
||||||
log.Fatalf("Theme generation failed: %v", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
request := map[string]any{
|
|
||||||
"id": 1,
|
|
||||||
"method": "matugen.queue",
|
|
||||||
"params": map[string]any{
|
|
||||||
"stateDir": opts.StateDir,
|
"stateDir": opts.StateDir,
|
||||||
"shellDir": opts.ShellDir,
|
"shellDir": opts.ShellDir,
|
||||||
"configDir": opts.ConfigDir,
|
"configDir": opts.ConfigDir,
|
||||||
@@ -144,11 +118,14 @@ func runMatugenQueue(cmd *cobra.Command, args []string) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.NewEncoder(conn).Encode(request); err != nil {
|
|
||||||
log.Fatalf("Failed to send request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !wait {
|
if !wait {
|
||||||
|
if err := sendServerRequestFireAndForget(request); err != nil {
|
||||||
|
log.Info("Server unavailable, running synchronously")
|
||||||
|
if err := matugen.Run(opts); err != nil {
|
||||||
|
log.Fatalf("Theme generation failed: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
fmt.Println("Theme generation queued")
|
fmt.Println("Theme generation queued")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -158,17 +135,18 @@ func runMatugenQueue(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
resultCh := make(chan error, 1)
|
resultCh := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
var response struct {
|
resp, ok := tryServerRequest(request)
|
||||||
ID int `json:"id"`
|
if !ok {
|
||||||
Result any `json:"result"`
|
log.Info("Server unavailable, running synchronously")
|
||||||
Error string `json:"error"`
|
if err := matugen.Run(opts); err != nil {
|
||||||
}
|
resultCh <- err
|
||||||
if err := json.NewDecoder(conn).Decode(&response); err != nil {
|
return
|
||||||
resultCh <- fmt.Errorf("failed to read response: %w", err)
|
}
|
||||||
|
resultCh <- nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if response.Error != "" {
|
if resp.Error != "" {
|
||||||
resultCh <- fmt.Errorf("server error: %s", response.Error)
|
resultCh <- fmt.Errorf("server error: %s", resp.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resultCh <- nil
|
resultCh <- nil
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"mime"
|
"mime"
|
||||||
"net"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -93,32 +90,6 @@ func mimeTypeToCategories(mimeType string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runOpen(target string) {
|
func runOpen(target string) {
|
||||||
socketPath, err := server.FindSocket()
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("DMS socket not found: %v", err)
|
|
||||||
fmt.Println("DMS is not running. Please start DMS first.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := net.Dial("unix", socketPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("DMS socket connection failed: %v", err)
|
|
||||||
fmt.Println("DMS is not running. Please start DMS first.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
buf := make([]byte, 1)
|
|
||||||
for {
|
|
||||||
_, err := conn.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if buf[0] == '\n' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse file:// URIs to extract the actual file path
|
// Parse file:// URIs to extract the actual file path
|
||||||
actualTarget := target
|
actualTarget := target
|
||||||
detectedMimeType := openMimeType
|
detectedMimeType := openMimeType
|
||||||
@@ -219,8 +190,9 @@ func runOpen(target string) {
|
|||||||
|
|
||||||
log.Infof("Sending request - Method: %s, Params: %+v", method, params)
|
log.Infof("Sending request - Method: %s, Params: %+v", method, params)
|
||||||
|
|
||||||
if err := json.NewEncoder(conn).Encode(req); err != nil {
|
if err := sendServerRequestFireAndForget(req); err != nil {
|
||||||
log.Fatalf("Failed to send request: %v", err)
|
fmt.Println("DMS is not running. Please start DMS first.")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Request sent successfully")
|
log.Infof("Request sent successfully")
|
||||||
|
|||||||
@@ -9,15 +9,10 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type serverResponse struct {
|
func sendServerRequest(req models.Request) (*models.Response[any], error) {
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
Result any `json:"result,omitempty"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendServerRequest(req map[string]any) (*serverResponse, error) {
|
|
||||||
socketPath := getServerSocketPath()
|
socketPath := getServerSocketPath()
|
||||||
|
|
||||||
conn, err := net.Dial("unix", socketPath)
|
conn, err := net.Dial("unix", socketPath)
|
||||||
@@ -46,7 +41,7 @@ func sendServerRequest(req map[string]any) (*serverResponse, error) {
|
|||||||
return nil, fmt.Errorf("failed to read response")
|
return nil, fmt.Errorf("failed to read response")
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp serverResponse
|
var resp models.Response[any]
|
||||||
if err := json.Unmarshal(scanner.Bytes(), &resp); err != nil {
|
if err := json.Unmarshal(scanner.Bytes(), &resp); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||||
}
|
}
|
||||||
@@ -54,6 +49,46 @@ func sendServerRequest(req map[string]any) (*serverResponse, error) {
|
|||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendServerRequestFireAndForget sends a request without waiting for a response.
|
||||||
|
// Useful for commands that trigger UI or async operations.
|
||||||
|
func sendServerRequestFireAndForget(req models.Request) error {
|
||||||
|
socketPath := getServerSocketPath()
|
||||||
|
|
||||||
|
conn, err := net.Dial("unix", socketPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to connect to server (is it running?): %w", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(conn)
|
||||||
|
scanner.Scan() // discard initial capabilities message
|
||||||
|
|
||||||
|
reqData, err := json.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.Write(reqData); err != nil {
|
||||||
|
return fmt.Errorf("failed to write request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.Write([]byte("\n")); err != nil {
|
||||||
|
return fmt.Errorf("failed to write newline: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryServerRequest attempts to send a request but returns false if server unavailable.
|
||||||
|
// Does not log errors - caller can decide what to do on failure.
|
||||||
|
func tryServerRequest(req models.Request) (*models.Response[any], bool) {
|
||||||
|
resp, err := sendServerRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return resp, true
|
||||||
|
}
|
||||||
|
|
||||||
func getServerSocketPath() string {
|
func getServerSocketPath() string {
|
||||||
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
||||||
if runtimeDir == "" {
|
if runtimeDir == "" {
|
||||||
|
|||||||
229
core/internal/mocks/wlclient/mock_WaylandDisplay.go
Normal file
229
core/internal/mocks/wlclient/mock_WaylandDisplay.go
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
// Code generated by mockery v2.53.5. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks_wlclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
client "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockWaylandDisplay is an autogenerated mock type for the WaylandDisplay type
|
||||||
|
type MockWaylandDisplay struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockWaylandDisplay_Expecter struct {
|
||||||
|
mock *mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_m *MockWaylandDisplay) EXPECT() *MockWaylandDisplay_Expecter {
|
||||||
|
return &MockWaylandDisplay_Expecter{mock: &_m.Mock}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandDisplay) Context() *client.Context {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Context")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *client.Context
|
||||||
|
if rf, ok := ret.Get(0).(func() *client.Context); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*client.Context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandDisplay_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context'
|
||||||
|
type MockWaylandDisplay_Context_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandDisplay_Expecter) Context() *MockWaylandDisplay_Context_Call {
|
||||||
|
return &MockWaylandDisplay_Context_Call{Call: _e.mock.On("Context")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Context_Call) Run(run func()) *MockWaylandDisplay_Context_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Context_Call) Return(_a0 *client.Context) *MockWaylandDisplay_Context_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Context_Call) RunAndReturn(run func() *client.Context) *MockWaylandDisplay_Context_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandDisplay) Destroy() error {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Destroy")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func() error); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandDisplay_Destroy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Destroy'
|
||||||
|
type MockWaylandDisplay_Destroy_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandDisplay_Expecter) Destroy() *MockWaylandDisplay_Destroy_Call {
|
||||||
|
return &MockWaylandDisplay_Destroy_Call{Call: _e.mock.On("Destroy")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Destroy_Call) Run(run func()) *MockWaylandDisplay_Destroy_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Destroy_Call) Return(_a0 error) *MockWaylandDisplay_Destroy_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Destroy_Call) RunAndReturn(run func() error) *MockWaylandDisplay_Destroy_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegistry provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandDisplay) GetRegistry() (*client.Registry, error) {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GetRegistry")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *client.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func() (*client.Registry, error)); ok {
|
||||||
|
return rf()
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func() *client.Registry); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*client.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func() error); ok {
|
||||||
|
r1 = rf()
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandDisplay_GetRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRegistry'
|
||||||
|
type MockWaylandDisplay_GetRegistry_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegistry is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandDisplay_Expecter) GetRegistry() *MockWaylandDisplay_GetRegistry_Call {
|
||||||
|
return &MockWaylandDisplay_GetRegistry_Call{Call: _e.mock.On("GetRegistry")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_GetRegistry_Call) Run(run func()) *MockWaylandDisplay_GetRegistry_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_GetRegistry_Call) Return(_a0 *client.Registry, _a1 error) *MockWaylandDisplay_GetRegistry_Call {
|
||||||
|
_c.Call.Return(_a0, _a1)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_GetRegistry_Call) RunAndReturn(run func() (*client.Registry, error)) *MockWaylandDisplay_GetRegistry_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roundtrip provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandDisplay) Roundtrip() error {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Roundtrip")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func() error); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandDisplay_Roundtrip_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Roundtrip'
|
||||||
|
type MockWaylandDisplay_Roundtrip_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roundtrip is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandDisplay_Expecter) Roundtrip() *MockWaylandDisplay_Roundtrip_Call {
|
||||||
|
return &MockWaylandDisplay_Roundtrip_Call{Call: _e.mock.On("Roundtrip")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Roundtrip_Call) Run(run func()) *MockWaylandDisplay_Roundtrip_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Roundtrip_Call) Return(_a0 error) *MockWaylandDisplay_Roundtrip_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandDisplay_Roundtrip_Call) RunAndReturn(run func() error) *MockWaylandDisplay_Roundtrip_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockWaylandDisplay creates a new instance of MockWaylandDisplay. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
// The first argument is typically a *testing.T value.
|
||||||
|
func NewMockWaylandDisplay(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *MockWaylandDisplay {
|
||||||
|
mock := &MockWaylandDisplay{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
||||||
226
core/internal/mocks/wlcontext/mock_WaylandContext.go
Normal file
226
core/internal/mocks/wlcontext/mock_WaylandContext.go
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
// Code generated by mockery v2.53.5. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks_wlcontext
|
||||||
|
|
||||||
|
import (
|
||||||
|
client "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockWaylandContext is an autogenerated mock type for the WaylandContext type
|
||||||
|
type MockWaylandContext struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockWaylandContext_Expecter struct {
|
||||||
|
mock *mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_m *MockWaylandContext) EXPECT() *MockWaylandContext_Expecter {
|
||||||
|
return &MockWaylandContext_Expecter{mock: &_m.Mock}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandContext) Close() {
|
||||||
|
_m.Called()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandContext_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
|
||||||
|
type MockWaylandContext_Close_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandContext_Expecter) Close() *MockWaylandContext_Close_Call {
|
||||||
|
return &MockWaylandContext_Close_Call{Call: _e.mock.On("Close")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Close_Call) Run(run func()) *MockWaylandContext_Close_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Close_Call) Return() *MockWaylandContext_Close_Call {
|
||||||
|
_c.Call.Return()
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Close_Call) RunAndReturn(run func()) *MockWaylandContext_Close_Call {
|
||||||
|
_c.Run(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandContext) Display() *client.Display {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Display")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *client.Display
|
||||||
|
if rf, ok := ret.Get(0).(func() *client.Display); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*client.Display)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandContext_Display_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Display'
|
||||||
|
type MockWaylandContext_Display_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandContext_Expecter) Display() *MockWaylandContext_Display_Call {
|
||||||
|
return &MockWaylandContext_Display_Call{Call: _e.mock.On("Display")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Display_Call) Run(run func()) *MockWaylandContext_Display_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Display_Call) Return(_a0 *client.Display) *MockWaylandContext_Display_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Display_Call) RunAndReturn(run func() *client.Display) *MockWaylandContext_Display_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// FatalError provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandContext) FatalError() <-chan error {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for FatalError")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 <-chan error
|
||||||
|
if rf, ok := ret.Get(0).(func() <-chan error); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(<-chan error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandContext_FatalError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FatalError'
|
||||||
|
type MockWaylandContext_FatalError_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// FatalError is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandContext_Expecter) FatalError() *MockWaylandContext_FatalError_Call {
|
||||||
|
return &MockWaylandContext_FatalError_Call{Call: _e.mock.On("FatalError")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_FatalError_Call) Run(run func()) *MockWaylandContext_FatalError_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_FatalError_Call) Return(_a0 <-chan error) *MockWaylandContext_FatalError_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_FatalError_Call) RunAndReturn(run func() <-chan error) *MockWaylandContext_FatalError_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post provides a mock function with given fields: fn
|
||||||
|
func (_m *MockWaylandContext) Post(fn func()) {
|
||||||
|
_m.Called(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandContext_Post_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Post'
|
||||||
|
type MockWaylandContext_Post_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post is a helper method to define mock.On call
|
||||||
|
// - fn func()
|
||||||
|
func (_e *MockWaylandContext_Expecter) Post(fn interface{}) *MockWaylandContext_Post_Call {
|
||||||
|
return &MockWaylandContext_Post_Call{Call: _e.mock.On("Post", fn)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Post_Call) Run(run func(fn func())) *MockWaylandContext_Post_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].(func()))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Post_Call) Return() *MockWaylandContext_Post_Call {
|
||||||
|
_c.Call.Return()
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Post_Call) RunAndReturn(run func(func())) *MockWaylandContext_Post_Call {
|
||||||
|
_c.Run(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start provides a mock function with no fields
|
||||||
|
func (_m *MockWaylandContext) Start() {
|
||||||
|
_m.Called()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockWaylandContext_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
|
||||||
|
type MockWaylandContext_Start_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start is a helper method to define mock.On call
|
||||||
|
func (_e *MockWaylandContext_Expecter) Start() *MockWaylandContext_Start_Call {
|
||||||
|
return &MockWaylandContext_Start_Call{Call: _e.mock.On("Start")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Start_Call) Run(run func()) *MockWaylandContext_Start_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run()
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Start_Call) Return() *MockWaylandContext_Start_Call {
|
||||||
|
_c.Call.Return()
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockWaylandContext_Start_Call) RunAndReturn(run func()) *MockWaylandContext_Start_Call {
|
||||||
|
_c.Run(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockWaylandContext creates a new instance of MockWaylandContext. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
// The first argument is typically a *testing.T value.
|
||||||
|
func NewMockWaylandContext(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *MockWaylandContext {
|
||||||
|
mock := &MockWaylandContext{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewManager(wlCtx *wlcontext.SharedContext, config Config) (*Manager, error) {
|
func NewManager(wlCtx wlcontext.WaylandContext, config Config) (*Manager, error) {
|
||||||
if config.Disabled {
|
if config.Disabled {
|
||||||
return nil, fmt.Errorf("clipboard disabled in config")
|
return nil, fmt.Errorf("clipboard disabled in config")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ package clipboard
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
mocks_wlcontext "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlcontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeDecodeEntry_Roundtrip(t *testing.T) {
|
func TestEncodeDecodeEntry_Roundtrip(t *testing.T) {
|
||||||
@@ -454,3 +458,74 @@ func TestDefaultConfig(t *testing.T) {
|
|||||||
assert.False(t, cfg.DisableHistory)
|
assert.False(t, cfg.DisableHistory)
|
||||||
assert.False(t, cfg.DisablePersist)
|
assert.False(t, cfg.DisablePersist)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestManager_PostDelegatesToWlContext(t *testing.T) {
|
||||||
|
mockCtx := mocks_wlcontext.NewMockWaylandContext(t)
|
||||||
|
|
||||||
|
var called atomic.Bool
|
||||||
|
mockCtx.EXPECT().Post(mock.AnythingOfType("func()")).Run(func(fn func()) {
|
||||||
|
called.Store(true)
|
||||||
|
fn()
|
||||||
|
}).Once()
|
||||||
|
|
||||||
|
m := &Manager{
|
||||||
|
wlCtx: mockCtx,
|
||||||
|
}
|
||||||
|
|
||||||
|
executed := false
|
||||||
|
m.post(func() {
|
||||||
|
executed = true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.True(t, called.Load())
|
||||||
|
assert.True(t, executed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestManager_PostExecutesFunctionViaContext(t *testing.T) {
|
||||||
|
mockCtx := mocks_wlcontext.NewMockWaylandContext(t)
|
||||||
|
|
||||||
|
var capturedFn func()
|
||||||
|
mockCtx.EXPECT().Post(mock.AnythingOfType("func()")).Run(func(fn func()) {
|
||||||
|
capturedFn = fn
|
||||||
|
}).Times(3)
|
||||||
|
|
||||||
|
m := &Manager{
|
||||||
|
wlCtx: mockCtx,
|
||||||
|
}
|
||||||
|
|
||||||
|
counter := 0
|
||||||
|
m.post(func() { counter++ })
|
||||||
|
m.post(func() { counter += 10 })
|
||||||
|
m.post(func() { counter += 100 })
|
||||||
|
|
||||||
|
assert.NotNil(t, capturedFn)
|
||||||
|
capturedFn()
|
||||||
|
assert.Equal(t, 100, counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestManager_ConcurrentPostWithMock(t *testing.T) {
|
||||||
|
mockCtx := mocks_wlcontext.NewMockWaylandContext(t)
|
||||||
|
|
||||||
|
var postCount atomic.Int32
|
||||||
|
mockCtx.EXPECT().Post(mock.AnythingOfType("func()")).Run(func(fn func()) {
|
||||||
|
postCount.Add(1)
|
||||||
|
}).Times(100)
|
||||||
|
|
||||||
|
m := &Manager{
|
||||||
|
wlCtx: mockCtx,
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for j := 0; j < 10; j++ {
|
||||||
|
m.post(func() {})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
assert.Equal(t, int32(100), postCount.Load())
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ type Manager struct {
|
|||||||
configMutex sync.RWMutex
|
configMutex sync.RWMutex
|
||||||
configPath string
|
configPath string
|
||||||
|
|
||||||
display *wlclient.Display
|
display wlclient.WaylandDisplay
|
||||||
wlCtx *wlcontext.SharedContext
|
wlCtx wlcontext.WaylandContext
|
||||||
|
|
||||||
registry *wlclient.Registry
|
registry *wlclient.Registry
|
||||||
dataControlMgr any
|
dataControlMgr any
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewManager(display *wlclient.Display) (*Manager, error) {
|
func NewManager(display wlclient.WaylandDisplay) (*Manager, error) {
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
display: display,
|
display: display,
|
||||||
ctx: display.Context(),
|
ctx: display.Context(),
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package dwl
|
package dwl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStateChanged_BothNil(t *testing.T) {
|
func TestStateChanged_BothNil(t *testing.T) {
|
||||||
@@ -350,3 +353,14 @@ func TestStateChanged_TagsLengthDiffers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.True(t, stateChanged(a, b))
|
assert.True(t, stateChanged(a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ type cmd struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
display *wlclient.Display
|
display wlclient.WaylandDisplay
|
||||||
ctx *wlclient.Context
|
ctx *wlclient.Context
|
||||||
registry *wlclient.Registry
|
registry *wlclient.Registry
|
||||||
manager any
|
manager any
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func CheckCapability() bool {
|
|||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManager(display *wlclient.Display) (*Manager, error) {
|
func NewManager(display wlclient.WaylandDisplay) (*Manager, error) {
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
display: display,
|
display: display,
|
||||||
ctx: display.Context(),
|
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 {
|
type Manager struct {
|
||||||
display *wlclient.Display
|
display wlclient.WaylandDisplay
|
||||||
ctx *wlclient.Context
|
ctx *wlclient.Context
|
||||||
registry *wlclient.Registry
|
registry *wlclient.Registry
|
||||||
manager *ext_workspace.ExtWorkspaceManagerV1
|
manager *ext_workspace.ExtWorkspaceManagerV1
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
const animKelvinStep = 25
|
const animKelvinStep = 25
|
||||||
|
|
||||||
func NewManager(display *wlclient.Display, config Config) (*Manager, error) {
|
func NewManager(display wlclient.WaylandDisplay, config Config) (*Manager, error) {
|
||||||
if err := config.Validate(); err != nil {
|
if err := config.Validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package wayland
|
package wayland
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestManager_ActorSerializesOutputStateAccess(t *testing.T) {
|
func TestManager_ActorSerializesOutputStateAccess(t *testing.T) {
|
||||||
@@ -384,3 +387,28 @@ func TestNotifySubscribers_NonBlocking(t *testing.T) {
|
|||||||
|
|
||||||
assert.Len(t, m.dirty, 1)
|
assert.Len(t, m.dirty, 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"))
|
||||||
|
|
||||||
|
config := DefaultConfig()
|
||||||
|
_, err := NewManager(mockDisplay, config)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "get registry")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewManager_InvalidConfig(t *testing.T) {
|
||||||
|
mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t)
|
||||||
|
|
||||||
|
config := Config{
|
||||||
|
LowTemp: 500,
|
||||||
|
HighTemp: 6500,
|
||||||
|
Gamma: 1.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := NewManager(mockDisplay, config)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ type Manager struct {
|
|||||||
state *State
|
state *State
|
||||||
stateMutex sync.RWMutex
|
stateMutex sync.RWMutex
|
||||||
|
|
||||||
display *wlclient.Display
|
display wlclient.WaylandDisplay
|
||||||
ctx *wlclient.Context
|
ctx *wlclient.Context
|
||||||
registry *wlclient.Registry
|
registry *wlclient.Registry
|
||||||
gammaControl any
|
gammaControl any
|
||||||
|
|||||||
@@ -12,6 +12,16 @@ import (
|
|||||||
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type WaylandContext interface {
|
||||||
|
Display() *wlclient.Display
|
||||||
|
Post(fn func())
|
||||||
|
FatalError() <-chan error
|
||||||
|
Start()
|
||||||
|
Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ WaylandContext = (*SharedContext)(nil)
|
||||||
|
|
||||||
type SharedContext struct {
|
type SharedContext struct {
|
||||||
display *wlclient.Display
|
display *wlclient.Display
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewManager(display *wlclient.Display) (*Manager, error) {
|
func NewManager(display wlclient.WaylandDisplay) (*Manager, error) {
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
display: display,
|
display: display,
|
||||||
ctx: display.Context(),
|
ctx: display.Context(),
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package wlroutput
|
package wlroutput
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStateChanged_BothNil(t *testing.T) {
|
func TestStateChanged_BothNil(t *testing.T) {
|
||||||
@@ -398,3 +401,14 @@ func TestStateChanged_IndexOutOfBounds(t *testing.T) {
|
|||||||
b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1"}, {Name: "HDMI-A-1"}}}
|
b := &State{Serial: 1, Outputs: []Output{{Name: "eDP-1"}, {Name: "HDMI-A-1"}}}
|
||||||
assert.True(t, stateChanged(a, b))
|
assert.True(t, stateChanged(a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ type cmd struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
display *wlclient.Display
|
display wlclient.WaylandDisplay
|
||||||
ctx *wlclient.Context
|
ctx *wlclient.Context
|
||||||
registry *wlclient.Registry
|
registry *wlclient.Registry
|
||||||
manager *wlr_output_management.ZwlrOutputManagerV1
|
manager *wlr_output_management.ZwlrOutputManagerV1
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ type Proxy interface {
|
|||||||
MarkZombie()
|
MarkZombie()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WaylandDisplay interface {
|
||||||
|
Context() *Context
|
||||||
|
GetRegistry() (*Registry, error)
|
||||||
|
Roundtrip() error
|
||||||
|
Destroy() error
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ WaylandDisplay = (*Display)(nil)
|
||||||
|
|
||||||
type BaseProxy struct {
|
type BaseProxy struct {
|
||||||
ctx *Context
|
ctx *Context
|
||||||
id uint32
|
id uint32
|
||||||
|
|||||||
Reference in New Issue
Block a user