blob: 75161937dbd26c7854dd9e2b083e94d5e670d9f7 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:typed_data';
import 'package:fidl/fidl.dart';
import 'package:fidl_fuchsia_io/fidl_async.dart';
import 'package:fuchsia_vfs/vfs.dart';
import 'package:test/test.dart';
import 'package:zircon/zircon.dart';
void main() {
const _newStr = 'new_str';
final _newStrList = Uint8List.fromList(_newStr.codeUnits);
InterfaceRequest<Node> _getNodeInterfaceRequest(FileProxy proxy) {
return InterfaceRequest<Node>(proxy.ctrl.request().passChannel());
}
_ReadOnlyFile _createReadOnlyFile(String str, OpenFlags openFlags,
[int expectedStatus = ZX.OK]) {
_ReadOnlyFile file = _ReadOnlyFile()
..pseudoFile = PseudoFile.readOnlyStr(() {
return str;
})
..proxy = FileProxy();
expect(
file.pseudoFile
.connect(openFlags, 0, _getNodeInterfaceRequest(file.proxy)),
expectedStatus);
return file;
}
Future<void> _assertFinalBuffer(FileProxy proxy, _ReadWriteFile file,
String oldStr, String newStr) async {
// our buffer should contain old string
expect(file.buffer, oldStr);
await proxy.close();
// our buffer should contain new string
expect(file.buffer, newStr);
}
Future<void> _assertWrite(FileProxy proxy, Uint8List content,
{int expectedStatus = ZX.OK, int? expectedSize}) async {
expectedSize ??= content.length;
if (expectedStatus == ZX.OK) {
final actualCount = await proxy.write(content);
expect(actualCount, expectedSize);
} else {
await expectLater(
proxy.write(content),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(expectedStatus))));
}
}
Future<void> _assertRead(FileProxy proxy, int bufSize, String expectedStr,
{expectedStatus = ZX.OK}) async {
if (expectedStatus == ZX.OK) {
final data = await proxy.read(bufSize);
expect(String.fromCharCodes(data), expectedStr);
} else {
await expectLater(
proxy.read(bufSize),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(expectedStatus))));
}
}
Future<void> _assertReadAt(
FileProxy proxy, int bufSize, int offset, String expectedStr,
{expectedStatus = ZX.OK}) async {
if (expectedStatus == ZX.OK) {
final data = await proxy.readAt(bufSize, offset);
expect(String.fromCharCodes(data), expectedStr);
} else {
await expectLater(
proxy.readAt(bufSize, offset),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(expectedStatus))));
}
}
Future<void> _assertWriteAt(
FileProxy proxy, Uint8List content, int offset, int expectedWrittenLen,
{expectedStatus = ZX.OK}) async {
if (expectedStatus == ZX.OK) {
final actualCount = await proxy.writeAt(content, offset);
expect(actualCount, expectedWrittenLen);
} else {
await expectLater(
proxy.writeAt(content, offset),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(expectedStatus))));
}
}
group('pseudo file creation validation: ', () {
PseudoFile _createReadWriteFileStub() {
return PseudoFile.readWriteStr(1, () {
return '';
}, (String str) {
return ZX.OK;
});
}
final _notAllowedFlags = [
OpenFlags.create,
OpenFlags.createIfAbsent,
];
test('onOpen event on flag validation error', () async {
final file = _createReadOnlyFile('',
OpenFlags.rightWritable | OpenFlags.describe, ZX.ERR_NOT_SUPPORTED);
await file.proxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_NOT_SUPPORTED);
expect(response.info, isNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('read only file', () async {
final file = _createReadOnlyFile(
'', OpenFlags.rightWritable, ZX.ERR_NOT_SUPPORTED);
{
final proxy = FileProxy();
expect(
file.pseudoFile.connect(
OpenFlags.truncate, 0, _getNodeInterfaceRequest(proxy)),
ZX.ERR_NOT_SUPPORTED);
}
{
final proxy = FileProxy();
expect(
file.pseudoFile.connect(
OpenFlags.directory, 0, _getNodeInterfaceRequest(proxy)),
ZX.ERR_NOT_DIR);
}
{
final proxy = FileProxy();
expect(
file.pseudoFile
.connect(OpenFlags.append, 0, _getNodeInterfaceRequest(proxy)),
ZX.ERR_INVALID_ARGS);
}
for (final flag in _notAllowedFlags) {
final proxy = FileProxy();
expect(
file.pseudoFile.connect(flag, 0, _getNodeInterfaceRequest(proxy)),
ZX.ERR_NOT_SUPPORTED,
reason: 'for flag: $flag');
}
});
test('read write file', () async {
final file = _createReadWriteFileStub();
{
final proxy = FileProxy();
expect(
file.connect(
OpenFlags.directory, 0, _getNodeInterfaceRequest(proxy)),
ZX.ERR_NOT_DIR);
}
{
final proxy = FileProxy();
expect(
file.connect(OpenFlags.append, 0, _getNodeInterfaceRequest(proxy)),
ZX.ERR_INVALID_ARGS);
}
for (final flag in _notAllowedFlags) {
final proxy = FileProxy();
expect(file.connect(flag, 0, _getNodeInterfaceRequest(proxy)),
ZX.ERR_NOT_SUPPORTED,
reason: 'for flag: $flag');
}
});
test('connect file with mode', () async {
final file = _createReadWriteFileStub();
{
final proxy = FileProxy();
expect(
file.connect(OpenFlags.rightReadable | OpenFlags.describe,
~modeTypeFile, _getNodeInterfaceRequest(proxy)),
ZX.ERR_INVALID_ARGS);
await proxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_INVALID_ARGS);
expect(response.info, isNull);
}).catchError((err) async {
fail(err.toString());
});
}
{
final proxy = FileProxy();
expect(
file.connect(OpenFlags.rightReadable | OpenFlags.describe,
modeTypeFile, _getNodeInterfaceRequest(proxy)),
ZX.OK);
await proxy.onOpen.first.then((response) {
expect(response.s, ZX.OK);
expect(response.info, isNotNull);
}).catchError((err) async {
fail(err.toString());
});
}
});
test('open fails', () async {
final file = _createReadWriteFileStub();
final paths = ['', '/', '.', './', './/', './//'];
for (final path in paths) {
final proxy = FileProxy();
file.open(OpenFlags.rightReadable | OpenFlags.describe, 0, path,
_getNodeInterfaceRequest(proxy), OpenFlags.rightReadable);
await proxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_NOT_DIR);
expect(response.info, isNull);
}).catchError((err) async {
fail(err.toString());
});
}
});
});
group('pseudo file:', () {
_ReadWriteFile _createReadWriteFile(String initialStr,
{int? capacity, createProxy = true, OpenFlags? flags}) {
int c = initialStr.length;
if (capacity != null) {
assert(capacity >= initialStr.length);
c = capacity;
}
_ReadWriteFile file = _ReadWriteFile();
file
..buffer = initialStr
..pseudoFile = PseudoFile.readWriteStr(c, () {
return file.buffer;
}, (String str) {
file.buffer = str;
return ZX.OK;
});
if (createProxy) {
file.proxy = FileProxy();
expect(
file.pseudoFile.connect(
flags ?? OpenFlags.rightReadable | OpenFlags.rightWritable,
0,
_getNodeInterfaceRequest(file.proxy)),
ZX.OK);
}
return file;
}
test('onOpen event on success', () async {
final file = _createReadOnlyFile(
'test_str', OpenFlags.rightReadable | OpenFlags.describe);
await file.proxy.onOpen.first.then((response) {
expect(response.s, ZX.OK);
expect(response.info, isNotNull);
}).catchError((err) async {
fail(err.toString());
});
});
final expectedNodeAttrs = NodeAttributes(
mode: modeTypeFile | modeProtectionMask,
id: inoUnknown,
contentSize: 0,
storageSize: 0,
linkCount: 1,
creationTime: 0,
modificationTime: 0);
test('test getAttr', () async {
final file = _createReadOnlyFile('test_str', OpenFlags.rightReadable);
final response = await file.proxy.getAttr();
expect(response.s, ZX.OK);
expect(response.attributes, expectedNodeAttrs);
});
test('clone works', () async {
final file = _createReadOnlyFile('test_str', OpenFlags.rightReadable);
final clonedProxy = FileProxy();
await file.proxy.clone(OpenFlags.rightReadable | OpenFlags.describe,
_getNodeInterfaceRequest(clonedProxy));
await clonedProxy.onOpen.first.then((response) {
expect(response.s, ZX.OK);
expect(response.info, isNotNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('clone works with POSIX compatibility flags', () async {
final file = _createReadOnlyFile('test_str', OpenFlags.rightReadable);
final clonedProxy = FileProxy();
await file.proxy.clone(
OpenFlags.rightReadable |
OpenFlags.describe |
OpenFlags.posixWritable |
OpenFlags.posixExecutable,
_getNodeInterfaceRequest(clonedProxy));
await clonedProxy.onOpen.first.then((response) {
expect(response.s, ZX.OK);
expect(response.info, isNotNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('clone fails when trying to pass Readable flag to Node Reference',
() async {
final file = _createReadOnlyFile(
'test_str', OpenFlags.rightReadable | OpenFlags.nodeReference);
final clonedProxy = FileProxy();
await file.proxy.clone(OpenFlags.rightReadable | OpenFlags.describe,
_getNodeInterfaceRequest(clonedProxy));
await clonedProxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_ACCESS_DENIED);
expect(response.info, isNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('clone fails when trying to pass Writable flag to Node Reference',
() async {
final file = _createReadWriteFile('test_str',
flags: OpenFlags.rightWritable | OpenFlags.nodeReference);
final clonedProxy = FileProxy();
await file.proxy.clone(OpenFlags.rightWritable | OpenFlags.describe,
_getNodeInterfaceRequest(clonedProxy));
await clonedProxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_ACCESS_DENIED);
expect(response.info, isNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('able to clone Node Reference', () async {
final file = _createReadOnlyFile('test_str', OpenFlags.nodeReference);
final clonedProxy = FileProxy();
await file.proxy.clone(OpenFlags.nodeReference | OpenFlags.describe,
_getNodeInterfaceRequest(clonedProxy));
await clonedProxy.onOpen.first.then((response) {
expect(response.s, ZX.OK);
expect(response.info, isNotNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('clone should fail if requested rights exceed source rights',
() async {
final file = _createReadWriteFile('test_str', createProxy: false);
final flagsToTest = [OpenFlags.rightReadable, OpenFlags.rightWritable];
for (final flag in flagsToTest) {
final proxy = FileProxy();
expect(
file.pseudoFile
.connect(OpenFlags.$none, 0, _getNodeInterfaceRequest(proxy)),
ZX.OK);
final clonedProxy = FileProxy();
await proxy.clone(
flag | OpenFlags.describe, _getNodeInterfaceRequest(clonedProxy));
await clonedProxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_ACCESS_DENIED);
expect(response.info, isNull);
}).catchError((err) async {
fail(err.toString());
});
}
});
test('onOpen with describe flag', () async {
final file = _createReadOnlyFile(
'test_str', OpenFlags.rightReadable | OpenFlags.describe);
await file.proxy.onOpen.first.then((response) {
expect(response.s, ZX.OK);
expect(response.info, isNotNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('onOpen with NodeReference flag', () async {
final file = _createReadOnlyFile(
'test_str', OpenFlags.nodeReference | OpenFlags.describe);
await file.proxy.onOpen.first.then((response) {
expect(response.s, ZX.OK);
expect(response.info, isNotNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('Directory not ignored with NodeReference flag', () async {
final file = _createReadOnlyFile(
'test_str',
OpenFlags.nodeReference | OpenFlags.describe | OpenFlags.directory,
ZX.ERR_NOT_DIR);
await file.proxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_NOT_DIR);
expect(response.info, isNull);
}).catchError((err) async {
fail(err.toString());
});
});
test('GetAttr with NodeReference flag', () async {
final file = _createReadOnlyFile('test_str', OpenFlags.nodeReference);
final response = await file.proxy.getAttr();
expect(response.s, ZX.OK);
expect(response.attributes, expectedNodeAttrs);
});
test('read file', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
await _assertRead(file.proxy, 10, str);
});
test('read functions fails for NodeReference flag', () async {
final file = _createReadOnlyFile(
'test_str', OpenFlags.rightReadable | OpenFlags.nodeReference);
await expectLater(
file.proxy.read(1024),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(ZX.ERR_ACCESS_DENIED))));
await expectLater(
file.proxy.readAt(0, 1024),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(ZX.ERR_ACCESS_DENIED))));
});
Future<void> _resetSeek(FileProxy proxy, [int? offset]) async {
// Reset seek.
int _ = await proxy.seek(SeekOrigin.start, offset ?? 0);
}
test('simple write file', () async {
const str = 'test_str';
final file = _createReadWriteFile(str);
final proxy = file.proxy;
await _assertWrite(proxy, _newStrList);
await _resetSeek(proxy);
await _assertRead(file.proxy, 100, _newStr);
await _assertFinalBuffer(file.proxy, file, str, _newStr);
});
test('readAt', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
for (int i = 0; i < str.length; i++) {
await _assertReadAt(file.proxy, 100, i, str.substring(i));
}
});
test('read after readAt', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
await _assertReadAt(file.proxy, 100, 1, str.substring(1));
//readAt should not change seek
await _assertRead(file.proxy, 100, str);
});
test('read should not affect readAt', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
await _assertRead(file.proxy, 100, str);
// after seek is changed, readAt should be able to read at any position
await _assertReadAt(file.proxy, 100, 2, str.substring(2));
});
test('readAt should work for arbitrary length', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
// try to read 3 chars
await _assertReadAt(file.proxy, 3, 2, str.substring(2, 2 + 3));
});
test('read should work after readAt read arbitrary length', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
await _assertReadAt(file.proxy, 3, 2, str.substring(2, 2 + 3));
await _assertRead(file.proxy, 3, str.substring(0, 0 + 3));
});
test('readAt should fail for passing offset more than length of file',
() async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
await _assertReadAt(file.proxy, 100, str.length + 1, '',
expectedStatus: ZX.ERR_OUT_OF_RANGE);
});
test('readAt should not fail for passing offset equal to length of file',
() async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
await _assertReadAt(file.proxy, 100, str.length, '');
});
test('read should not fail for reading from end of file', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
await _resetSeek(file.proxy, str.length);
await _assertRead(file.proxy, 100, '');
});
test('write file at arbitrary position', () async {
const str = 'test_str';
final file = _createReadWriteFile(str);
final proxy = file.proxy;
await _resetSeek(proxy, 1);
await _assertWrite(proxy, _newStrList);
await _resetSeek(proxy);
final expectedStr = str.substring(0, 1) + _newStr;
await _assertRead(proxy, 100, expectedStr);
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('write should truncate if not enough capacity', () async {
const str = 'test_str';
final file = _createReadWriteFile(str);
final proxy = file.proxy;
await _resetSeek(proxy, 2);
await _assertWrite(proxy, _newStrList, expectedSize: _newStr.length - 1);
await _resetSeek(proxy);
final expectedStr =
str.substring(0, 2) + _newStr.substring(0, _newStr.length - 1);
await _assertRead(proxy, 100, expectedStr);
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('write at end should fail', () async {
const str = 'test_str';
final file = _createReadWriteFile(str);
final proxy = file.proxy;
await _resetSeek(proxy, str.length);
await _assertWrite(proxy, _newStrList,
expectedStatus: ZX.ERR_OUT_OF_RANGE, expectedSize: 0);
await _resetSeek(proxy);
await _assertRead(proxy, 100, str);
await _assertFinalBuffer(proxy, file, str, str);
});
group('write file when capacity is not initial length:', () {
test('should not resize if there is enough capacity', () async {
const str = 'test_str';
final file = _createReadWriteFile(str, capacity: str.length + 2);
final proxy = file.proxy;
await _resetSeek(proxy, 3);
await _assertWrite(proxy, _newStrList);
final expectedStr =
str.substring(0, 3) + _newStr.substring(0, _newStr.length);
await _assertReadAt(proxy, 100, 0, expectedStr);
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('write should fail when capacity is reached', () async {
const str = 'test_str';
final file = _createReadWriteFile(str, capacity: str.length + 2);
final proxy = file.proxy;
await _resetSeek(proxy, 3);
await _assertWrite(proxy, _newStrList);
final expectedStr =
str.substring(0, 3) + _newStr.substring(0, _newStr.length);
// write at end, should fail
await _resetSeek(proxy, expectedStr.length);
await _assertWrite(proxy, _newStrList,
expectedStatus: ZX.ERR_OUT_OF_RANGE, expectedSize: 0);
// no write should have happened
await _assertReadAt(proxy, 100, 0, expectedStr);
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('write to end of initial len', () async {
const str = 'test_str';
final file = _createReadWriteFile(str, capacity: str.length + 2);
final proxy = file.proxy;
await _resetSeek(proxy, str.length);
// write at end
await _assertWrite(proxy, _newStrList, expectedSize: 2);
final expectedStr = str + _newStr.substring(0, 2);
await _assertReadAt(proxy, 100, 0, expectedStr);
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('writeAt should not depend on seek', () async {
const str = 'test_str';
final file = _createReadWriteFile(str, capacity: str.length + 2);
final proxy = file.proxy;
await _resetSeek(proxy, str.length);
// seek is at end, write at 2nd position
await _assertWriteAt(proxy, _newStrList, 2, _newStrList.length);
// seek should not have changed
final expectedStr = str.substring(0, 2) + _newStr;
await _assertRead(proxy, 100, expectedStr.substring(str.length));
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('writeAt - end of file with', () async {
const str = 'test_str';
// writeAt should be able to write at end of the file
final file = _createReadWriteFile(str, capacity: str.length + 5);
final proxy = file.proxy;
await _assertWriteAt(proxy, _newStrList, str.length, 5);
final expectedStr = str + _newStr.substring(0, 5);
await _assertRead(proxy, 100, expectedStr);
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('writeAt should fail for trying to write beyond end of file',
() async {
const str = 'test_str';
final file = _createReadWriteFile(str, capacity: str.length + 5);
final proxy = file.proxy;
await _assertWriteAt(proxy, _newStrList, str.length + 1, 0,
expectedStatus: ZX.ERR_OUT_OF_RANGE);
await _assertRead(proxy, 100, str);
await _assertFinalBuffer(proxy, file, str, str);
});
test('write functions fails for NodeReference flag', () async {
const str = 'test_str';
final file = _createReadWriteFile(str,
capacity: str.length + 5,
flags: OpenFlags.rightWritable | OpenFlags.nodeReference);
final proxy = file.proxy;
await _assertWriteAt(proxy, _newStrList, str.length + 1, 0,
expectedStatus: ZX.ERR_ACCESS_DENIED);
await _assertWrite(proxy, _newStrList,
expectedSize: 0, expectedStatus: ZX.ERR_ACCESS_DENIED);
});
});
test('various seek positions and reads', () async {
const str = 'a very big string';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
final proxy = file.proxy;
{
const c = 5;
final data = await proxy.read(5);
expect(String.fromCharCodes(data), str.substring(0, c));
}
var lastOffset = 5;
{
const c = 6;
final data = await proxy.read(6);
expect(String.fromCharCodes(data),
str.substring(lastOffset, lastOffset + c));
}
{
const c = 10;
int offsetFromStart = await proxy.seek(SeekOrigin.start, c);
expect(offsetFromStart, c);
final data = await proxy.read(100);
expect(String.fromCharCodes(data), str.substring(c));
}
{
const c = 2;
final offsetFromStart = await proxy.seek(SeekOrigin.start, c);
expect(offsetFromStart, c);
lastOffset = c;
}
{
const c = 5;
final offsetFromStart = await proxy.seek(SeekOrigin.current, c);
expect(offsetFromStart, c + lastOffset);
lastOffset = offsetFromStart;
final data = await proxy.read(100);
expect(String.fromCharCodes(data), str.substring(lastOffset));
}
{
const c = 0;
final offsetFromStart = await proxy.seek(SeekOrigin.end, c);
expect(offsetFromStart, str.length - 1);
}
{
const c = -3;
final offsetFromStart = await proxy.seek(SeekOrigin.end, c);
expect(offsetFromStart, str.length - 1 + c);
final data = await proxy.read(100);
expect(String.fromCharCodes(data), str.substring(offsetFromStart));
}
// Check edge and error conditions
{
const c = 3;
await expectLater(
proxy.seek(SeekOrigin.end, c),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(ZX.ERR_OUT_OF_RANGE))));
}
{
const c = -3;
await expectLater(
proxy.seek(SeekOrigin.start, c),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(ZX.ERR_OUT_OF_RANGE))));
}
{
const c = 5;
final offsetFromStart = await proxy.seek(SeekOrigin.start, c);
await expectLater(
proxy.seek(SeekOrigin.current, str.length - offsetFromStart + 1),
throwsA(isA<MethodException>()
.having((e) => e.value, 'value', equals(ZX.ERR_OUT_OF_RANGE))));
}
});
group('resize: ', () {
test('failure test', () async {
const str = 'test_str';
final file = _createReadWriteFile(str, createProxy: false);
final proxy = FileProxy();
expect(
file.pseudoFile.connect(
OpenFlags.rightReadable, 0, _getNodeInterfaceRequest(proxy)),
ZX.OK);
await expectLater(
proxy.resize(3),
throwsA(isA<MethodException>().having(
(e) => e.value, 'value', equals(ZX.ERR_ACCESS_DENIED))));
await _assertRead(proxy, 100, str);
await _assertFinalBuffer(proxy, file, str, str);
});
test('basic', () async {
const str = 'test_str';
final file = _createReadWriteFile(str);
final proxy = file.proxy;
await proxy.resize(3);
final expectedStr = str.substring(0, 3);
await _assertRead(proxy, 100, expectedStr);
await _assertFinalBuffer(proxy, file, str, expectedStr);
});
test('on open', () async {
const str = 'test_str';
final file = _createReadWriteFile(str, createProxy: false);
final proxy = FileProxy();
expect(
file.pseudoFile.connect(
OpenFlags.rightReadable |
OpenFlags.rightWritable |
OpenFlags.truncate,
0,
_getNodeInterfaceRequest(proxy)),
ZX.OK);
await _assertFinalBuffer(proxy, file, str, '');
});
test('with seek', () async {
const str = 'test_str';
final file = _createReadWriteFile(str);
final proxy = file.proxy;
await _resetSeek(proxy, 5);
await proxy.resize(3);
// seek and currentLen should be 3 so we should not get any data
await _assertRead(proxy, 100, '');
// resize should have worked
await _assertReadAt(proxy, 100, 0, str.substring(0, 3));
});
test('close should work', () async {
const str = 'test_str';
final file = _createReadOnlyFile(str, OpenFlags.rightReadable);
// make sure file was opened
file.pseudoFile.close();
file.proxy.ctrl.whenClosed.asStream().listen(expectAsync1((_) {}));
});
});
});
}
class _ReadOnlyFile {
late PseudoFile pseudoFile;
late FileProxy proxy;
}
class _ReadWriteFile {
String? buffer;
late PseudoFile pseudoFile;
late FileProxy proxy;
}