From 024d2ff7826a81db65eefa1843730b537ebdeef1 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Wed, 3 Sep 2025 02:16:10 +0900 Subject: [PATCH] system: improve tests of the I struct This cleans up for the test overhaul of this package. Signed-off-by: Ophestra --- system/acl.go | 2 +- system/link.go | 2 +- system/mkdir.go | 2 +- system/output_test.go | 18 ++++--- system/system.go | 9 ++-- system/system_test.go | 121 ++++++++++++++++++++++++++---------------- system/wayland.go | 2 +- system/xhost.go | 2 +- 8 files changed, 95 insertions(+), 63 deletions(-) diff --git a/system/acl.go b/system/acl.go index 0432056..127b90b 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 4ba74ff..544443e 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 4fba4af..9b92c0f 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 9ad949c..2dfa337 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 e8fa43f..1a65363 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 323e35b..cbe3dfc 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 999feee..f6e5051 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 2ed1acf..22a0669 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)