| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| // Testing file input stream, VM-only, standalone test. |
| // |
| // OtherResources=readuntil_test.dat |
| // OtherResources=readline_test1.dat |
| // OtherResources=readline_test2.dat |
| |
| // @dart = 2.9 |
| |
| import "dart:convert"; |
| import "dart:io"; |
| |
| import "package:async_helper/async_helper.dart"; |
| import "package:expect/expect.dart"; |
| |
| String getFilename(String path) { |
| return Platform.script.resolve(path).toFilePath(); |
| } |
| |
| void testStringLineSplitter() { |
| String fileName = getFilename("readuntil_test.dat"); |
| // File contains "Hello Dart\nwassup!\n" |
| File file = new File(fileName); |
| int linesRead = 0; |
| var lineStream = file |
| .openRead() |
| .cast<List<int>>() |
| .transform(utf8.decoder) |
| .transform(new LineSplitter()); |
| lineStream.listen((line) { |
| linesRead++; |
| if (linesRead == 1) { |
| Expect.equals("Hello Dart", line); |
| } else if (linesRead == 2) { |
| Expect.equals("wassup!", line); |
| } else { |
| Expect.fail("More or less than 2 lines read ($linesRead lines read)."); |
| } |
| }); |
| } |
| |
| void testOpenStreamAsync() { |
| asyncStart(); |
| String fileName = getFilename("readuntil_test.dat"); |
| // File contains "Hello Dart\nwassup!\n" |
| var expected = "Hello Dart\nwassup!\n".codeUnits; |
| var byteCount = 0; |
| (new File(fileName)).openRead().listen((d) => byteCount += d.length, |
| onDone: () { |
| Expect.equals(expected.length, byteCount); |
| asyncEnd(); |
| }); |
| } |
| |
| // Create a file that is big enough that a file stream will |
| // read it in multiple chunks. |
| int writeLongFileSync(File file) { |
| file.createSync(); |
| StringBuffer buffer = new StringBuffer(); |
| for (var i = 0; i < 50000; i++) { |
| buffer.write("Hello, world"); |
| } |
| file.writeAsStringSync(buffer.toString()); |
| var length = file.lengthSync(); |
| Expect.equals(buffer.length, length); |
| return length; |
| } |
| |
| void testInputStreamTruncate() { |
| asyncStart(); |
| var temp = Directory.systemTemp.createTempSync('file_input_stream_test'); |
| var file = new File('${temp.path}/input_stream_truncate.txt'); |
| var originalLength = writeLongFileSync(file); |
| // Start streaming the file. Pause after first chunk. Truncate |
| // underlying file and check that the streaming stops with or |
| // without getting all data. |
| var streamedBytes = 0; |
| var subscription; |
| subscription = file.openRead().listen((d) { |
| if (streamedBytes == 0) { |
| subscription.pause(); |
| // Truncate the file by opening it for writing. |
| file.open(mode: FileMode.write).then((opened) { |
| opened.close().then((_) { |
| Expect.equals(0, file.lengthSync()); |
| subscription.resume(); |
| }); |
| }); |
| } |
| streamedBytes += d.length; |
| }, onDone: () { |
| Expect.isTrue(streamedBytes > 0 && streamedBytes <= originalLength); |
| temp.delete(recursive: true).then((_) => asyncEnd()); |
| }, onError: (e) { |
| Expect.fail("Unexpected error"); |
| }); |
| } |
| |
| void testInputStreamDelete() { |
| asyncStart(); |
| var temp = Directory.systemTemp.createTempSync('file_input_stream_test'); |
| var file = new File('${temp.path}/input_stream_delete.txt'); |
| var originalLength = writeLongFileSync(file); |
| // Start streaming the file. Pause after first chunk. Truncate |
| // underlying file and check that the streaming stops with or |
| // without getting all data. |
| var streamedBytes = 0; |
| var subscription; |
| subscription = file.openRead().listen((d) { |
| if (streamedBytes == 0) { |
| subscription.pause(); |
| // Delete the underlying file by opening it for writing. |
| file.delete().then((deleted) { |
| Expect.isFalse(deleted.existsSync()); |
| subscription.resume(); |
| }).catchError((e) { |
| // On Windows, you cannot delete a file that is open |
| // somewhere else. The stream has this file open |
| // and therefore we get an error on deletion on Windows. |
| Expect.equals('windows', Platform.operatingSystem); |
| subscription.resume(); |
| }); |
| } |
| streamedBytes += d.length; |
| }, onDone: () { |
| Expect.equals(originalLength, streamedBytes); |
| temp.delete(recursive: true).then((_) => asyncEnd()); |
| }, onError: (e) { |
| Expect.fail("Unexpected error"); |
| }); |
| } |
| |
| void testInputStreamAppend() { |
| asyncStart(); |
| var temp = Directory.systemTemp.createTempSync('file_input_stream_test'); |
| var file = new File('${temp.path}/input_stream_append.txt'); |
| var originalLength = writeLongFileSync(file); |
| // Start streaming the file. Pause after first chunk. Append to |
| // underlying file and check that the stream gets all the data. |
| var streamedBytes = 0; |
| var subscription; |
| subscription = file.openRead().listen((d) { |
| if (streamedBytes == 0) { |
| subscription.pause(); |
| // Double the length of the underlying file. |
| file.readAsBytes().then((bytes) { |
| file.writeAsBytes(bytes, mode: FileMode.append).then((_) { |
| Expect.equals(2 * originalLength, file.lengthSync()); |
| subscription.resume(); |
| }); |
| }); |
| } |
| streamedBytes += d.length; |
| }, onDone: () { |
| Expect.equals(2 * originalLength, streamedBytes); |
| temp.delete(recursive: true).then((_) => asyncEnd()); |
| }, onError: (e) { |
| Expect.fail("Unexpected error"); |
| }); |
| } |
| |
| void testInputStreamOffset() { |
| void test(int start, int end, int expectedBytes) { |
| asyncStart(); |
| var temp = Directory.systemTemp.createTempSync('file_input_stream_test'); |
| var file = new File('${temp.path}/input_stream_offset.txt'); |
| var originalLength = writeLongFileSync(file); |
| var streamedBytes = 0; |
| if (expectedBytes < 0) expectedBytes = originalLength + expectedBytes; |
| file.openRead(start, end).listen((d) { |
| streamedBytes += d.length; |
| }, onDone: () { |
| Expect.equals(expectedBytes, streamedBytes); |
| temp.delete(recursive: true).then((_) => asyncEnd()); |
| }, onError: (e) { |
| Expect.fail("Unexpected error"); |
| }); |
| } |
| |
| test(10, 20, 10); |
| test(10, 11, 1); |
| test(10, 10, 0); |
| test(100000000, null, 0); |
| test(null, 0, 0); |
| test(null, 1, 1); |
| test(1, null, -1); |
| test(20, null, -20); |
| } |
| |
| void testInputStreamBadOffset() { |
| void test(int start, int end) { |
| asyncStart(); |
| var temp = Directory.systemTemp.createTempSync('file_input_stream_test'); |
| var file = new File('${temp.path}/input_stream_bad_offset.txt'); |
| var originalLength = writeLongFileSync(file); |
| var streamedBytes = 0; |
| bool error = false; |
| file.openRead(start, end).listen((d) { |
| streamedBytes += d.length; |
| }, onDone: () { |
| Expect.isTrue(error); |
| temp.deleteSync(recursive: true); |
| asyncEnd(); |
| }, onError: (e) { |
| error = true; |
| }); |
| } |
| |
| test(-1, null); |
| test(100, 99); |
| test(null, -1); |
| } |
| |
| void testStringLineSplitterEnding(String name, int length) { |
| String fileName = getFilename(name); |
| // File contains 10 lines. |
| File file = new File(fileName); |
| Expect.equals(length, file.lengthSync()); |
| var lineStream = file |
| .openRead() |
| .cast<List<int>>() |
| .transform(utf8.decoder) |
| .transform(new LineSplitter()); |
| int lineCount = 0; |
| lineStream.listen((line) { |
| lineCount++; |
| Expect.isTrue(lineCount <= 10); |
| if (line[0] != "#") { |
| Expect.equals("Line $lineCount", line); |
| } |
| }, onDone: () { |
| Expect.equals(10, lineCount); |
| }); |
| } |
| |
| main() { |
| testStringLineSplitter(); |
| testOpenStreamAsync(); |
| testInputStreamTruncate(); |
| testInputStreamDelete(); |
| testInputStreamAppend(); |
| testInputStreamOffset(); |
| testInputStreamBadOffset(); |
| // Check the length of these files as both are text files where one |
| // is without a terminating line separator which can easily be added |
| // back if accidentally opened in a text editor. |
| testStringLineSplitterEnding("readline_test1.dat", 111); |
| testStringLineSplitterEnding("readline_test2.dat", 114); |
| } |