aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/uevent/uevent_test.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-03-28 00:10:50 +0900
committerOphestra <cat@gensokyo.uk>2026-03-28 00:49:34 +0900
commit713bff3eb0a77efff016acc02b6f10913810f887 (patch)
treea648ab320007bf1aa15ab2f55e7856713cf92e88 /internal/uevent/uevent_test.go
parent30f459e690ca561d3932cb6efa0cf14ea53c25b2 (diff)
internal/uevent: decode uevent messages
The wire format and behaviour is entirely undocumented. This is implemented by reading lib/kobject_uevent.c, with testdata collected from the internal/rosa kernel. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/uevent/uevent_test.go')
-rw-r--r--internal/uevent/uevent_test.go84
1 files changed, 76 insertions, 8 deletions
diff --git a/internal/uevent/uevent_test.go b/internal/uevent/uevent_test.go
index 9af3dcdd..53d9bafc 100644
--- a/internal/uevent/uevent_test.go
+++ b/internal/uevent/uevent_test.go
@@ -2,7 +2,6 @@ package uevent_test
import (
"encoding"
- "fmt"
"reflect"
"testing"
@@ -14,13 +13,14 @@ func adeT[V any, S interface {
encoding.TextAppender
encoding.TextMarshaler
encoding.TextUnmarshaler
- fmt.Stringer
*V
}](t *testing.T, name string, v V, want string, wantErr, wantErrE error) {
t.Helper()
- t.Run(name, func(t *testing.T) {
- t.Parallel()
+ f := func(t *testing.T) {
+ if name != "" {
+ t.Parallel()
+ }
t.Helper()
t.Run("decode", func(t *testing.T) {
@@ -49,15 +49,63 @@ func adeT[V any, S interface {
} else if err == nil && string(got) != want {
t.Errorf("MarshalText: %q, want %q", string(got), want)
}
- if wantErrE != nil {
+ })
+ }
+ if name != "" {
+ t.Run(name, f)
+ } else {
+ f(t)
+ }
+}
+
+// adeT sets up a binary subtest for a textual appender/decoder/encoder.
+func adeB[V any, S interface {
+ encoding.BinaryAppender
+ encoding.BinaryMarshaler
+ encoding.BinaryUnmarshaler
+
+ *V
+}](t *testing.T, name string, v V, want string, wantErr, wantErrE error) {
+ t.Helper()
+ f := func(t *testing.T) {
+ if name != "" {
+ t.Parallel()
+ }
+ t.Helper()
+
+ t.Run("decode", func(t *testing.T) {
+ t.Parallel()
+ t.Helper()
+
+ var got V
+ if err := S(&got).UnmarshalBinary([]byte(want)); !reflect.DeepEqual(err, wantErr) {
+ t.Fatalf("UnmarshalBinary: error = %v, want %v", err, wantErr)
+ }
+ if wantErr != nil {
return
}
- if got := S(&v).String(); got != want {
- t.Errorf("String: %q, want %q", got, want)
+ if !reflect.DeepEqual(&got, &v) {
+ t.Errorf("UnmarshalBinary: %#v, want %#v", got, v)
}
})
- })
+
+ t.Run("encode", func(t *testing.T) {
+ t.Parallel()
+ t.Helper()
+
+ if got, err := S(&v).MarshalBinary(); !reflect.DeepEqual(err, wantErrE) {
+ t.Fatalf("MarshalBinary: error = %v, want %v", err, wantErrE)
+ } else if err == nil && string(got) != want {
+ t.Errorf("MarshalBinary: %q, want %q", string(got), want)
+ }
+ })
+ }
+ if name != "" {
+ t.Run(name, f)
+ } else {
+ f(t)
+ }
}
func TestErrors(t *testing.T) {
@@ -70,6 +118,26 @@ func TestErrors(t *testing.T) {
}{
{"UnsupportedActionError", uevent.UnsupportedActionError("explode"),
`unsupported kobject_action "explode"`},
+
+ {"MissingHeaderError", uevent.MissingHeaderError("move"),
+ `message "move" has no header`},
+
+ {"MessageError MErrorKindHeaderSep", &uevent.MessageError{
+ Data: "move\x00",
+ Section: "move",
+ Kind: uevent.MErrorKindHeaderSep,
+ }, `header "move" missing separator`},
+
+ {"MessageError MErrorKindFinalNUL", &uevent.MessageError{
+ Data: "move\x00truncated",
+ Section: "truncated",
+ Kind: uevent.MErrorKindFinalNUL,
+ }, `entry "truncated" missing NUL`},
+
+ {"MessageError bad", &uevent.MessageError{
+ Data: "\x00",
+ Kind: 0xbad,
+ }, `section "" is invalid`},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {