aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-09-03 02:16:10 +0900
committerOphestra <cat@gensokyo.uk>2025-09-03 02:16:10 +0900
commit024d2ff7826a81db65eefa1843730b537ebdeef1 (patch)
treeb3d9048c075fec0759bd8886a07a252ca0ce4555
parent6f719bc3c19d56279d2d76d3bcf8fb66ace2d2fb (diff)
system: improve tests of the I struct
This cleans up for the test overhaul of this package. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--system/acl.go2
-rw-r--r--system/link.go2
-rw-r--r--system/mkdir.go2
-rw-r--r--system/output_test.go18
-rw-r--r--system/system.go9
-rw-r--r--system/system_test.go121
-rw-r--r--system/wayland.go2
-rw-r--r--system/xhost.go2
8 files changed, 95 insertions, 63 deletions
diff --git a/system/acl.go b/system/acl.go
index 04320563..127b90b6 100644
--- a/system/acl.go
+++ b/system/acl.go
@@ -36,7 +36,7 @@ func (a *ACLUpdateOp) apply(sys *I) error {
}
func (a *ACLUpdateOp) revert(sys *I, ec *Criteria) error {
- if ec.hasType(a) {
+ if ec.hasType(a.Type()) {
msg.Verbose("stripping ACL", a)
err := acl.Update(a.path, sys.uid)
if errors.Is(err, os.ErrNotExist) {
diff --git a/system/link.go b/system/link.go
index 4ba74ff9..544443e9 100644
--- a/system/link.go
+++ b/system/link.go
@@ -28,7 +28,7 @@ func (l *HardlinkOp) apply(*I) error {
}
func (l *HardlinkOp) revert(_ *I, ec *Criteria) error {
- if ec.hasType(l) {
+ if ec.hasType(l.Type()) {
msg.Verbosef("removing hard link %q", l.dst)
return newOpError("hardlink", os.Remove(l.dst), true)
} else {
diff --git a/system/mkdir.go b/system/mkdir.go
index 4fba4afd..9b92c0f9 100644
--- a/system/mkdir.go
+++ b/system/mkdir.go
@@ -50,7 +50,7 @@ func (m *MkdirOp) revert(_ *I, ec *Criteria) error {
return nil
}
- if ec.hasType(m) {
+ if ec.hasType(m.Type()) {
msg.Verbose("destroying ephemeral directory", m)
return newOpError("mkdir", os.Remove(m.path), true)
} else {
diff --git a/system/output_test.go b/system/output_test.go
index 9ad949c3..2dfa337d 100644
--- a/system/output_test.go
+++ b/system/output_test.go
@@ -209,18 +209,22 @@ func (ptc tcOp) test(t *testing.T, gotOps []Op, wantOps []Op, fn string) {
t.Run("criteria", func(t *testing.T) {
testCases := []struct {
name string
- ec *Criteria
+ ec Enablement
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},
+ {"nil", 0xff, ptc.et != User},
+ {"self", ptc.et, true},
+ {"all", EWayland | EX11 | EDBus | EPulse | User | Process, true},
+ {"enablements", 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 {
+ var criteria *Criteria
+ if tc.ec != 0xff {
+ criteria = (*Criteria)(&tc.ec)
+ }
+ if got := criteria.hasType(o.Type()); got != tc.want {
t.Errorf("hasType: got %v, want %v",
got, tc.want)
}
@@ -229,5 +233,3 @@ func (ptc tcOp) test(t *testing.T, gotOps []Op, wantOps []Op, fn string) {
})
}
}
-
-func newCriteria(e Enablement) *Criteria { return (*Criteria)(&e) }
diff --git a/system/system.go b/system/system.go
index e8fa43fa..1a653636 100644
--- a/system/system.go
+++ b/system/system.go
@@ -20,13 +20,13 @@ const (
// Criteria specifies types of Op to revert.
type Criteria Enablement
-func (ec *Criteria) hasType(o Op) bool {
+func (ec *Criteria) hasType(t Enablement) bool {
// nil criteria: revert everything except User
if ec == nil {
- return o.Type() != User
+ return t != User
}
- return Enablement(*ec)&o.Type() != 0
+ return Enablement(*ec)&t != 0
}
// Op is a reversible system operation.
@@ -92,7 +92,7 @@ func (sys *I) UID() int { return sys.uid }
// Equal returns whether all [Op] instances held by sys matches that of target.
func (sys *I) Equal(target *I) bool {
- if target == nil || sys.uid != target.uid || len(sys.ops) != len(target.ops) {
+ if sys == nil || target == nil || sys.uid != target.uid || len(sys.ops) != len(target.ops) {
return false
}
@@ -149,7 +149,6 @@ func (sys *I) Revert(ec *Criteria) error {
// collect errors
errs := make([]error, len(sys.ops))
-
for i := range sys.ops {
errs[i] = sys.ops[len(sys.ops)-i-1].revert(sys, ec)
}
diff --git a/system/system_test.go b/system/system_test.go
index 323e35b0..cbe3dfc4 100644
--- a/system/system_test.go
+++ b/system/system_test.go
@@ -1,28 +1,37 @@
package system_test
import (
+ "reflect"
"strconv"
"testing"
+ _ "unsafe"
"hakurei.app/system"
)
-func TestNew(t *testing.T) {
+//go:linkname criteriaHasType hakurei.app/system.(*Criteria).hasType
+func criteriaHasType(_ *system.Criteria, _ system.Enablement) bool
+
+func TestCriteria(t *testing.T) {
testCases := []struct {
- uid int
+ name string
+ ec, t system.Enablement
+ want bool
}{
- {150},
- {149},
- {148},
- {147},
+ {"nil", 0xff, system.EWayland, true},
+ {"nil user", 0xff, system.User, false},
+ {"all", system.EWayland | system.EX11 | system.EDBus | system.EPulse | system.User | system.Process, system.Process, true},
}
for _, tc := range testCases {
- t.Run("sys initialised with uid "+strconv.Itoa(tc.uid), func(t *testing.T) {
- if got := system.New(t.Context(), tc.uid); got.UID() != tc.uid {
- t.Errorf("New(%d) uid = %d, want %d",
- tc.uid,
- got.UID(), tc.uid)
+ t.Run(tc.name, func(t *testing.T) {
+ var criteria *system.Criteria
+ if tc.ec != 0xff {
+ criteria = (*system.Criteria)(&tc.ec)
+ }
+ if got := criteriaHasType(criteria, tc.t); got != tc.want {
+ t.Errorf("hasType: got %v, want %v",
+ got, tc.want)
}
})
}
@@ -45,86 +54,108 @@ func TestTypeString(t *testing.T) {
}
for _, tc := range testCases {
- t.Run("label type string "+tc.want, func(t *testing.T) {
+ t.Run("label type string "+strconv.Itoa(int(tc.e)), func(t *testing.T) {
if got := system.TypeString(tc.e); got != tc.want {
- t.Errorf("TypeString: %q, want %q",
- got, tc.want)
+ t.Errorf("TypeString: %q, want %q", got, tc.want)
}
})
}
}
-func TestI_Equal(t *testing.T) {
+func TestNew(t *testing.T) {
+ t.Run("panic", func(t *testing.T) {
+ t.Run("ctx", func(t *testing.T) {
+ defer func() {
+ want := "invalid call to New"
+ if r := recover(); r != want {
+ t.Errorf("recover: %v, want %v", r, want)
+ }
+ }()
+ system.New(nil, 0)
+ })
+
+ t.Run("uid", func(t *testing.T) {
+ defer func() {
+ want := "invalid call to New"
+ if r := recover(); r != want {
+ t.Errorf("recover: %v, want %v", r, want)
+ }
+ }()
+ system.New(t.Context(), -1)
+ })
+ })
+
+ sys := system.New(t.Context(), 0xdeadbeef)
+ if got := reflect.ValueOf(sys).Elem().FieldByName("ctx"); got.IsNil() {
+ t.Errorf("New: ctx = %#v", got)
+ }
+ if got := sys.UID(); got != 0xdeadbeef {
+ t.Errorf("UID: %d", got)
+ }
+}
+
+func TestEqual(t *testing.T) {
testCases := []struct {
name string
sys *system.I
v *system.I
want bool
}{
- {
- "simple UID",
+ {"simple UID",
system.New(t.Context(), 150),
system.New(t.Context(), 150),
- true,
- },
- {
- "simple UID differ",
+ true},
+
+ {"simple UID differ",
system.New(t.Context(), 150),
system.New(t.Context(), 151),
- false,
- },
- {
- "simple UID nil",
+ false},
+
+ {"simple UID nil",
system.New(t.Context(), 150),
nil,
- false,
- },
- {
- "op length mismatch",
+ false},
+
+ {"op length mismatch",
system.New(t.Context(), 150).
ChangeHosts("chronos"),
system.New(t.Context(), 150).
ChangeHosts("chronos").
Ensure("/run", 0755),
- false,
- },
- {
- "op value mismatch",
+ false},
+
+ {"op value mismatch",
system.New(t.Context(), 150).
ChangeHosts("chronos").
Ensure("/run", 0644),
system.New(t.Context(), 150).
ChangeHosts("chronos").
Ensure("/run", 0755),
- false,
- },
- {
- "op type mismatch",
+ false},
+
+ {"op type mismatch",
system.New(t.Context(), 150).
ChangeHosts("chronos").
CopyFile(new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 0, 256),
system.New(t.Context(), 150).
ChangeHosts("chronos").
Ensure("/run", 0755),
- false,
- },
- {
- "op equals",
+ false},
+
+ {"op equals",
system.New(t.Context(), 150).
ChangeHosts("chronos").
Ensure("/run", 0755),
system.New(t.Context(), 150).
ChangeHosts("chronos").
Ensure("/run", 0755),
- true,
- },
+ true},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.sys.Equal(tc.v) != tc.want {
- t.Errorf("Equal: got %v; want %v",
- !tc.want, tc.want)
+ t.Errorf("Equal: %v, want %v", !tc.want, tc.want)
}
})
}
diff --git a/system/wayland.go b/system/wayland.go
index 999feee7..f6e50511 100644
--- a/system/wayland.go
+++ b/system/wayland.go
@@ -59,7 +59,7 @@ func (w *WaylandOp) apply(sys *I) error {
}
func (w *WaylandOp) revert(_ *I, ec *Criteria) error {
- if ec.hasType(w) {
+ if ec.hasType(w.Type()) {
msg.Verbosef("removing wayland socket on %q", w.dst)
if err := os.Remove(w.dst); err != nil && !errors.Is(err, os.ErrNotExist) {
return newOpError("wayland", err, true)
diff --git a/system/xhost.go b/system/xhost.go
index 2ed1acff..22a0669f 100644
--- a/system/xhost.go
+++ b/system/xhost.go
@@ -22,7 +22,7 @@ func (x XHostOp) apply(*I) error {
}
func (x XHostOp) revert(_ *I, ec *Criteria) error {
- if ec.hasType(x) {
+ if ec.hasType(x.Type()) {
msg.Verbosef("deleting entry %s from X11", x)
return newOpError("xhost",
xcb.ChangeHosts(xcb.HostModeDelete, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)), false)