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