forked from rosa/hakurei
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>
152 lines
3.3 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|