Files
hakurei/internal/uevent/uevent_test.go
Ophestra 713bff3eb0
All checks were successful
Test / Create distribution (push) Successful in 1m14s
Test / Sandbox (push) Successful in 3m3s
Test / Hakurei (push) Successful in 4m13s
Test / ShareFS (push) Successful in 4m17s
Test / Sandbox (race detector) (push) Successful in 5m35s
Test / Hakurei (race detector) (push) Successful in 6m38s
Test / Flake checks (push) Successful in 1m24s
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>
2026-03-28 00:49:34 +09:00

152 lines
3.3 KiB
Go

package uevent_test
import (
"encoding"
"reflect"
"testing"
"hakurei.app/internal/uevent"
)
// adeT sets up a parallel subtest for a textual appender/decoder/encoder.
func adeT[V any, S interface {
encoding.TextAppender
encoding.TextMarshaler
encoding.TextUnmarshaler
*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).UnmarshalText([]byte(want)); !reflect.DeepEqual(err, wantErr) {
t.Fatalf("UnmarshalText: error = %v, want %v", err, wantErr)
}
if wantErr != nil {
return
}
if !reflect.DeepEqual(&got, &v) {
t.Errorf("UnmarshalText: %#v, want %#v", got, v)
}
})
t.Run("encode", func(t *testing.T) {
t.Parallel()
t.Helper()
if got, err := S(&v).MarshalText(); !reflect.DeepEqual(err, wantErrE) {
t.Fatalf("MarshalText: error = %v, want %v", err, wantErrE)
} else if err == nil && string(got) != want {
t.Errorf("MarshalText: %q, want %q", string(got), want)
}
})
}
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 !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) {
t.Parallel()
testCases := []struct {
name string
err error
want string
}{
{"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) {
t.Parallel()
if got := tc.err.Error(); got != tc.want {
t.Errorf("Error: %q, want %q", got, tc.want)
}
})
}
}