All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 1m51s
Test / Hakurei (push) Successful in 3m18s
Test / Hpkg (push) Successful in 3m41s
Test / Sandbox (race detector) (push) Successful in 4m7s
Test / Hakurei (race detector) (push) Successful in 5m18s
Test / Flake checks (push) Successful in 1m35s
This passes more information allowing for better error handling. This eliminates generic WrapErr from system. Signed-off-by: Ophestra <cat@gensokyo.uk>
190 lines
4.6 KiB
Go
190 lines
4.6 KiB
Go
package system
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"os"
|
|
"reflect"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"hakurei.app/container"
|
|
"hakurei.app/internal/hlog"
|
|
)
|
|
|
|
func TestOpError(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
err error
|
|
s string
|
|
is error
|
|
isF error
|
|
}{
|
|
{"message", newOpErrorMessage("dbus", ErrDBusConfig,
|
|
"attempted to create message bus proxy args without session bus config", false),
|
|
"attempted to create message bus proxy args without session bus config",
|
|
ErrDBusConfig, syscall.ENOTRECOVERABLE},
|
|
|
|
{"apply", newOpError("tmpfile", syscall.EBADE, false),
|
|
"cannot apply tmpfile: invalid exchange",
|
|
syscall.EBADE, syscall.EBADF},
|
|
|
|
{"revert", newOpError("wayland", syscall.EBADF, true),
|
|
"cannot revert wayland: bad file descriptor",
|
|
syscall.EBADF, syscall.EBADE},
|
|
|
|
{"path", newOpError("tmpfile", &os.PathError{Op: "stat", Path: "/run/dbus", Err: syscall.EISDIR}, false),
|
|
"stat /run/dbus: is a directory",
|
|
syscall.EISDIR, syscall.ENOTDIR},
|
|
|
|
{"net", newOpError("wayland", &net.OpError{Op: "dial", Net: "unix", Addr: &net.UnixAddr{Name: "/run/user/1000/wayland-1", Net: "unix"}, Err: syscall.ENOENT}, false),
|
|
"dial unix /run/user/1000/wayland-1: no such file or directory",
|
|
syscall.ENOENT, syscall.EPERM},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Run("error", func(t *testing.T) {
|
|
if got := tc.err.Error(); got != tc.s {
|
|
t.Errorf("Error: %q, want %q", got, tc.s)
|
|
}
|
|
})
|
|
t.Run("is", func(t *testing.T) {
|
|
if !errors.Is(tc.err, tc.is) {
|
|
t.Error("Is: unexpected false")
|
|
}
|
|
if errors.Is(tc.err, tc.isF) {
|
|
t.Error("Is: unexpected true")
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
t.Run("new", func(t *testing.T) {
|
|
if err := newOpError("check", nil, false); err != nil {
|
|
t.Errorf("newOpError: %v", err)
|
|
}
|
|
if err := newOpErrorMessage("check", nil, "", false); err != nil {
|
|
t.Errorf("newOpErrorMessage: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSetOutput(t *testing.T) {
|
|
oldmsg := msg
|
|
t.Cleanup(func() { msg = oldmsg })
|
|
msg = nil
|
|
|
|
t.Run("nil", func(t *testing.T) {
|
|
SetOutput(nil)
|
|
if _, ok := msg.(*container.DefaultMsg); !ok {
|
|
t.Errorf("SetOutput: %#v", msg)
|
|
}
|
|
})
|
|
|
|
t.Run("hlog", func(t *testing.T) {
|
|
SetOutput(hlog.Output{})
|
|
if _, ok := msg.(hlog.Output); !ok {
|
|
t.Errorf("SetOutput: %#v", msg)
|
|
}
|
|
})
|
|
|
|
t.Run("reset", func(t *testing.T) {
|
|
SetOutput(nil)
|
|
if _, ok := msg.(*container.DefaultMsg); !ok {
|
|
t.Errorf("SetOutput: %#v", msg)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPrintJoinedError(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
err error
|
|
want [][]any
|
|
}{
|
|
{"nil", nil, [][]any{{"not a joined error:", nil}}},
|
|
{"unwrapped", syscall.EINVAL, [][]any{{"not a joined error:", syscall.EINVAL}}},
|
|
{"single", errors.Join(syscall.EINVAL), [][]any{{"invalid argument"}}},
|
|
|
|
{"many", errors.Join(syscall.ENOTRECOVERABLE, syscall.ETIMEDOUT, syscall.EBADFD), [][]any{
|
|
{"state not recoverable"},
|
|
{"connection timed out"},
|
|
{"file descriptor in bad state"},
|
|
}},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
var got [][]any
|
|
printJoinedError(func(v ...any) { got = append(got, v) }, "not a joined error:", tc.err)
|
|
if !reflect.DeepEqual(got, tc.want) {
|
|
t.Errorf("printJoinedError: %#v, want %#v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type tcOp struct {
|
|
et Enablement
|
|
path string
|
|
}
|
|
|
|
// test an instance of the Op interface
|
|
func (ptc tcOp) test(t *testing.T, gotOps []Op, wantOps []Op, fn string) {
|
|
if len(gotOps) != len(wantOps) {
|
|
t.Errorf("%s: inserted %v Ops, want %v", fn,
|
|
len(gotOps), len(wantOps))
|
|
return
|
|
}
|
|
|
|
t.Run("path", func(t *testing.T) {
|
|
if len(gotOps) > 0 {
|
|
if got := gotOps[0].Path(); got != ptc.path {
|
|
t.Errorf("Path() = %q, want %q",
|
|
got, ptc.path)
|
|
return
|
|
}
|
|
}
|
|
})
|
|
|
|
for i := range gotOps {
|
|
o := gotOps[i]
|
|
|
|
t.Run("is", func(t *testing.T) {
|
|
if !o.Is(o) {
|
|
t.Errorf("Is returned false on self")
|
|
return
|
|
}
|
|
if !o.Is(wantOps[i]) {
|
|
t.Errorf("%s: inserted %#v, want %#v",
|
|
fn,
|
|
o, wantOps[i])
|
|
return
|
|
}
|
|
})
|
|
|
|
t.Run("criteria", func(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
ec *Criteria
|
|
want bool
|
|
}{
|
|
{"nil", nil, ptc.et != User},
|
|
{"self", newCriteria(ptc.et), true},
|
|
{"all", newCriteria(EWayland | EX11 | EDBus | EPulse | User | Process), true},
|
|
{"enablements", newCriteria(EWayland | EX11 | EDBus | EPulse), ptc.et != User && ptc.et != Process},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := tc.ec.hasType(o); got != tc.want {
|
|
t.Errorf("hasType: got %v, want %v",
|
|
got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func newCriteria(e Enablement) *Criteria { return (*Criteria)(&e) }
|