// 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 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>() .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>() .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); }