system/tmpfiles: do not fail for smaller files
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m23s
Test / Hpkg (push) Successful in 4m9s
Test / Sandbox (race detector) (push) Successful in 4m31s
Test / Hakurei (race detector) (push) Successful in 5m15s
Test / Hakurei (push) Successful in 2m11s
Test / Flake checks (push) Successful in 1m27s
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m23s
Test / Hpkg (push) Successful in 4m9s
Test / Sandbox (race detector) (push) Successful in 4m31s
Test / Hakurei (race detector) (push) Successful in 5m15s
Test / Hakurei (push) Successful in 2m11s
Test / Flake checks (push) Successful in 1m27s
The limit is meant to be an upper bound. Handle EOF and print verbose message for it instead of failing. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
323d132c40
commit
da2b9c01ce
@ -1,12 +1,20 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type osFile interface {
|
||||||
|
Name() string
|
||||||
|
io.Writer
|
||||||
|
fs.File
|
||||||
|
}
|
||||||
|
|
||||||
// syscallDispatcher provides methods that make state-dependent system calls as part of their behaviour.
|
// syscallDispatcher provides methods that make state-dependent system calls as part of their behaviour.
|
||||||
// syscallDispatcher is embedded in [I], so all methods must be unexported.
|
// syscallDispatcher is embedded in [I], so all methods must be unexported.
|
||||||
type syscallDispatcher interface {
|
type syscallDispatcher interface {
|
||||||
@ -15,6 +23,10 @@ type syscallDispatcher interface {
|
|||||||
// just synchronising access is not enough, as this is for test instrumentation.
|
// just synchronising access is not enough, as this is for test instrumentation.
|
||||||
new(f func(k syscallDispatcher))
|
new(f func(k syscallDispatcher))
|
||||||
|
|
||||||
|
// stat provides os.Stat.
|
||||||
|
stat(name string) (os.FileInfo, error)
|
||||||
|
// open provides [os.Open].
|
||||||
|
open(name string) (osFile, error)
|
||||||
// mkdir provides os.Mkdir.
|
// mkdir provides os.Mkdir.
|
||||||
mkdir(name string, perm os.FileMode) error
|
mkdir(name string, perm os.FileMode) error
|
||||||
// chmod provides os.Chmod.
|
// chmod provides os.Chmod.
|
||||||
@ -48,6 +60,8 @@ type direct struct{}
|
|||||||
|
|
||||||
func (k direct) new(f func(k syscallDispatcher)) { go f(k) }
|
func (k direct) new(f func(k syscallDispatcher)) { go f(k) }
|
||||||
|
|
||||||
|
func (k direct) stat(name string) (os.FileInfo, error) { return os.Stat(name) }
|
||||||
|
func (k direct) open(name string) (osFile, error) { return os.Open(name) }
|
||||||
func (k direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) }
|
func (k direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) }
|
||||||
func (k direct) chmod(name string, mode os.FileMode) error { return os.Chmod(name, mode) }
|
func (k direct) chmod(name string, mode os.FileMode) error { return os.Chmod(name, mode) }
|
||||||
func (k direct) link(oldname, newname string) error { return os.Link(oldname, newname) }
|
func (k direct) link(oldname, newname string) error { return os.Link(oldname, newname) }
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
@ -180,6 +183,34 @@ func checkOpMeta(t *testing.T, testCases []opMetaTestCase) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stubFi struct {
|
||||||
|
size int64
|
||||||
|
isDir bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stubFi) Name() string { panic("unreachable") }
|
||||||
|
func (fi stubFi) Size() int64 { return fi.size }
|
||||||
|
func (stubFi) Mode() fs.FileMode { panic("unreachable") }
|
||||||
|
func (stubFi) ModTime() time.Time { panic("unreachable") }
|
||||||
|
func (fi stubFi) IsDir() bool { return fi.isDir }
|
||||||
|
func (stubFi) Sys() any { panic("unreachable") }
|
||||||
|
|
||||||
|
type readerOsFile struct {
|
||||||
|
closed bool
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*readerOsFile) Name() string { panic("unreachable") }
|
||||||
|
func (*readerOsFile) Write([]byte) (int, error) { panic("unreachable") }
|
||||||
|
func (*readerOsFile) Stat() (fs.FileInfo, error) { panic("unreachable") }
|
||||||
|
func (r *readerOsFile) Close() error {
|
||||||
|
if r.closed {
|
||||||
|
return os.ErrClosed
|
||||||
|
}
|
||||||
|
r.closed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// InternalNew initialises [I] with a stub syscallDispatcher.
|
// InternalNew initialises [I] with a stub syscallDispatcher.
|
||||||
func InternalNew(t *testing.T, want stub.Expect, uid int) (*I, *stub.Stub[syscallDispatcher]) {
|
func InternalNew(t *testing.T, want stub.Expect, uid int) (*I, *stub.Stub[syscallDispatcher]) {
|
||||||
k := stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{s} }, want)
|
k := stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{s} }, want)
|
||||||
@ -192,6 +223,28 @@ type kstub struct{ *stub.Stub[syscallDispatcher] }
|
|||||||
|
|
||||||
func (k *kstub) new(f func(k syscallDispatcher)) { k.Helper(); k.New(f) }
|
func (k *kstub) new(f func(k syscallDispatcher)) { k.Helper(); k.New(f) }
|
||||||
|
|
||||||
|
func (k *kstub) stat(name string) (fi os.FileInfo, err error) {
|
||||||
|
k.Helper()
|
||||||
|
expect := k.Expects("stat")
|
||||||
|
err = expect.Error(
|
||||||
|
stub.CheckArg(k.Stub, "name", name, 0))
|
||||||
|
if err == nil {
|
||||||
|
fi = expect.Ret.(os.FileInfo)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *kstub) open(name string) (f osFile, err error) {
|
||||||
|
k.Helper()
|
||||||
|
expect := k.Expects("open")
|
||||||
|
err = expect.Error(
|
||||||
|
stub.CheckArg(k.Stub, "name", name, 0))
|
||||||
|
if err == nil {
|
||||||
|
f = expect.Ret.(osFile)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (k *kstub) mkdir(name string, perm os.FileMode) error {
|
func (k *kstub) mkdir(name string, perm os.FileMode) error {
|
||||||
k.Helper()
|
k.Helper()
|
||||||
return k.Expects("mkdir").Error(
|
return k.Expects("mkdir").Error(
|
||||||
|
@ -28,15 +28,15 @@ type tmpfileOp struct {
|
|||||||
|
|
||||||
func (t *tmpfileOp) Type() Enablement { return Process }
|
func (t *tmpfileOp) Type() Enablement { return Process }
|
||||||
|
|
||||||
func (t *tmpfileOp) apply(*I) error {
|
func (t *tmpfileOp) apply(sys *I) error {
|
||||||
msg.Verbose("copying", t)
|
|
||||||
|
|
||||||
if t.payload == nil {
|
if t.payload == nil {
|
||||||
// this is a misuse of the API; do not return an error message
|
// this is a misuse of the API; do not return a wrapped error
|
||||||
return errors.New("invalid payload")
|
return errors.New("invalid payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
if b, err := os.Stat(t.src); err != nil {
|
sys.verbose("copying", t)
|
||||||
|
|
||||||
|
if b, err := sys.stat(t.src); err != nil {
|
||||||
return newOpError("tmpfile", err, false)
|
return newOpError("tmpfile", err, false)
|
||||||
} else {
|
} else {
|
||||||
if b.IsDir() {
|
if b.IsDir() {
|
||||||
@ -47,9 +47,20 @@ func (t *tmpfileOp) apply(*I) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f, err := os.Open(t.src); err != nil {
|
var r io.ReadCloser
|
||||||
|
if f, err := sys.open(t.src); err != nil {
|
||||||
return newOpError("tmpfile", err, false)
|
return newOpError("tmpfile", err, false)
|
||||||
} else if _, err = io.CopyN(t.buf, f, t.n); err != nil {
|
} else {
|
||||||
|
r = f
|
||||||
|
}
|
||||||
|
if n, err := io.CopyN(t.buf, r, t.n); err != nil {
|
||||||
|
if !errors.Is(err, io.EOF) {
|
||||||
|
_ = r.Close()
|
||||||
|
return newOpError("tmpfile", err, false)
|
||||||
|
}
|
||||||
|
sys.verbosef("copied %d bytes from %q", n, t.src)
|
||||||
|
}
|
||||||
|
if err := r.Close(); err != nil {
|
||||||
return newOpError("tmpfile", err, false)
|
return newOpError("tmpfile", err, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,44 +1,142 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/container/stub"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCopyFile(t *testing.T) {
|
type errorReader struct{}
|
||||||
testCases := []struct {
|
|
||||||
tcOp
|
|
||||||
cap int
|
|
||||||
n int64
|
|
||||||
}{
|
|
||||||
{tcOp{Process, "/home/ophestra/xdg/config/pulse/cookie"}, 256, 256},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run("copy file "+tc.path+" with cap = "+strconv.Itoa(tc.cap)+" n = "+strconv.Itoa(int(tc.n)), func(t *testing.T) {
|
|
||||||
sys := New(t.Context(), 150)
|
|
||||||
sys.CopyFile(new([]byte), tc.path, tc.cap, tc.n)
|
|
||||||
tc.test(t, sys.ops, []Op{
|
|
||||||
&tmpfileOp{nil, tc.path, tc.n, nil},
|
|
||||||
}, "CopyFile")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTmpfile_String(t *testing.T) {
|
func (errorReader) Read([]byte) (int, error) { return 0, stub.UniqueError(0xdeadbeef) }
|
||||||
testCases := []struct {
|
|
||||||
src string
|
func TestTmpfileOp(t *testing.T) {
|
||||||
n int64
|
// 255 bytes
|
||||||
want string
|
const paSample = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||||
}{
|
|
||||||
{"/home/ophestra/xdg/config/pulse/cookie", 256,
|
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||||
|
{"payload", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
nil, "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, nil, errors.New("invalid payload"), nil, nil},
|
||||||
|
|
||||||
|
{"stat", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, nil, stub.UniqueError(1)),
|
||||||
|
}, &OpError{Op: "tmpfile", Err: stub.UniqueError(1)}, nil, nil},
|
||||||
|
|
||||||
|
{"stat EISDIR", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, stubFi{1 << 8, true}, nil),
|
||||||
|
}, &OpError{Op: "tmpfile", Err: &os.PathError{Op: "stat", Path: "/home/ophestra/xdg/config/pulse/cookie", Err: syscall.EISDIR}}, nil, nil},
|
||||||
|
|
||||||
|
{"stat ENOMEM", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, stubFi{1<<8 + 1, false}, nil),
|
||||||
|
}, &OpError{Op: "tmpfile", Err: &os.PathError{Op: "stat", Path: "/home/ophestra/xdg/config/pulse/cookie", Err: syscall.ENOMEM}}, nil, nil},
|
||||||
|
|
||||||
|
{"open", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, stubFi{1 << 8, false}, nil),
|
||||||
|
call("open", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, nil, stub.UniqueError(0)),
|
||||||
|
}, &OpError{Op: "tmpfile", Err: stub.UniqueError(0)}, nil, nil},
|
||||||
|
|
||||||
|
{"reader", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, stubFi{1 << 8, false}, nil),
|
||||||
|
call("open", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, &readerOsFile{true, errorReader{}}, nil),
|
||||||
|
}, &OpError{Op: "tmpfile", Err: stub.UniqueError(0xdeadbeef)}, nil, nil},
|
||||||
|
|
||||||
|
{"closed", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, stubFi{1 << 8, false}, nil),
|
||||||
|
call("open", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, &readerOsFile{true, strings.NewReader(paSample + "=")}, nil),
|
||||||
|
}, &OpError{Op: "tmpfile", Err: os.ErrClosed}, nil, nil},
|
||||||
|
|
||||||
|
{"success full", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, stubFi{1 << 8, false}, nil),
|
||||||
|
call("open", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, &readerOsFile{false, strings.NewReader(paSample + "=")}, nil),
|
||||||
|
}, nil, nil, nil},
|
||||||
|
|
||||||
|
{"success", 0xdead, 0xff, &tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}, []stub.Call{
|
||||||
|
call("verbose", stub.ExpectArgs{[]any{"copying", &tmpfileOp{new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }()}}}, nil, nil),
|
||||||
|
call("stat", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, stubFi{1 << 8, false}, nil),
|
||||||
|
call("open", stub.ExpectArgs{"/home/ophestra/xdg/config/pulse/cookie"}, &readerOsFile{false, strings.NewReader(paSample)}, nil),
|
||||||
|
call("verbosef", stub.ExpectArgs{"copied %d bytes from %q", []any{int64(1<<8 - 1), "/home/ophestra/xdg/config/pulse/cookie"}}, nil, nil),
|
||||||
|
}, nil, nil, nil},
|
||||||
|
})
|
||||||
|
|
||||||
|
checkOpsBuilder(t, "CopyFile", []opsBuilderTestCase{
|
||||||
|
{"pulse", 0xcafebabe, func(_ *testing.T, sys *I) {
|
||||||
|
sys.CopyFile(new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1<<8, 1<<8)
|
||||||
|
}, []Op{&tmpfileOp{
|
||||||
|
new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 1 << 8,
|
||||||
|
func() *bytes.Buffer { buf := new(bytes.Buffer); buf.Grow(1 << 8); return buf }(),
|
||||||
|
}}, stub.Expect{}},
|
||||||
|
})
|
||||||
|
|
||||||
|
checkOpIs(t, []opIsTestCase{
|
||||||
|
{"nil", (*tmpfileOp)(nil), (*tmpfileOp)(nil), false},
|
||||||
|
{"zero", new(tmpfileOp), new(tmpfileOp), true},
|
||||||
|
|
||||||
|
{"n differs", &tmpfileOp{
|
||||||
|
src: "/home/ophestra/xdg/config/pulse/cookie",
|
||||||
|
n: 1 << 7,
|
||||||
|
}, &tmpfileOp{
|
||||||
|
src: "/home/ophestra/xdg/config/pulse/cookie",
|
||||||
|
n: 1 << 8,
|
||||||
|
}, false},
|
||||||
|
|
||||||
|
{"src differs", &tmpfileOp{
|
||||||
|
src: "/home/ophestra/xdg/config/pulse",
|
||||||
|
n: 1 << 8,
|
||||||
|
}, &tmpfileOp{
|
||||||
|
src: "/home/ophestra/xdg/config/pulse/cookie",
|
||||||
|
n: 1 << 8,
|
||||||
|
}, false},
|
||||||
|
|
||||||
|
{"equals", &tmpfileOp{
|
||||||
|
src: "/home/ophestra/xdg/config/pulse/cookie",
|
||||||
|
n: 1 << 8,
|
||||||
|
}, &tmpfileOp{
|
||||||
|
src: "/home/ophestra/xdg/config/pulse/cookie",
|
||||||
|
n: 1 << 8,
|
||||||
|
}, true},
|
||||||
|
})
|
||||||
|
|
||||||
|
checkOpMeta(t, []opMetaTestCase{
|
||||||
|
{"pulse", &tmpfileOp{nil, "/home/ophestra/xdg/config/pulse/cookie", 1 << 8, nil},
|
||||||
|
Process, "/home/ophestra/xdg/config/pulse/cookie",
|
||||||
`up to 256 bytes from "/home/ophestra/xdg/config/pulse/cookie"`},
|
`up to 256 bytes from "/home/ophestra/xdg/config/pulse/cookie"`},
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.want, func(t *testing.T) {
|
|
||||||
if got := (&tmpfileOp{src: tc.src, n: tc.n}).String(); got != tc.want {
|
|
||||||
t.Errorf("String() = %v, want %v", got, tc.want)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user