Files
factorio-clusterio/test/lib/stream.js
T
Hornwitser 170a3d3cf7 Use stream.finished for detecting end of streams
There are some corner cases with streams that cause them to not emit
finish close or end events which in turn means that code liseting for
these events directly may end up hanging forever.  Use stream.finished
to detect end of streams which will handle these cases correctly.
2021-12-19 03:21:00 +01:00

152 lines
4.8 KiB
JavaScript

"use strict";
const assert = require("assert").strict;
const events = require("events");
const fs = require("fs-extra");
const path = require("path");
const stream = require("stream");
const util = require("util");
const libStream = require("@clusterio/lib/stream");
const finished = util.promisify(stream.finished);
describe("lib/stream", function() {
describe("class LineSplitter", function() {
function createSplitter(lines) {
let lineStream = new libStream.LineSplitter({ readableObjectMode: true });
lineStream.on("data", line => lines.push(line.toString("utf-8")));
return lineStream;
}
it("should split three lines", function() {
let lines = [];
let ls = createSplitter(lines);
ls.write(Buffer.from("line 1\nline 2\nline 3\n"));
ls.end();
assert.deepEqual(lines, ["line 1", "line 2", "line 3"]);
});
it("should split three Windows line endings lines", function() {
let lines = [];
let ls = createSplitter(lines);
ls.write(Buffer.from("line 1\r\nline 2\r\nline 3\r\n"));
ls.end();
assert.deepEqual(lines, ["line 1", "line 2", "line 3"]);
});
it("should handle mixed line endings", function() {
let lines = [];
let ls = createSplitter(lines);
ls.write(Buffer.from("1\n\n2\r\n\r\n3\n4"));
ls.end();
assert.deepEqual(lines, ["1", "", "2", "", "3", "4"]);
});
it("should give the last non-terminated line on .end()", function() {
let lines = [];
let ls = createSplitter(lines);
ls.write(Buffer.from("line a\nline b"));
assert.deepEqual(lines, ["line a"]);
ls.end();
assert.deepEqual(lines, ["line a", "line b"]);
});
it("should handled partial lines", function() {
let lines = [];
let ls = createSplitter(lines);
ls.write(Buffer.from("part 1"));
ls.write(Buffer.from(" part 2 "));
ls.write(Buffer.from("part 3\n"));
ls.end();
assert.deepEqual(lines, ["part 1 part 2 part 3"]);
});
});
describe("class ReverseLineSplitter", function() {
function createReverseSplitter(lines) {
let lineStream = new libStream.ReverseLineSplitter({ readableObjectMode: true });
lineStream.on("data", line => lines.push(line.toString("utf-8")));
return lineStream;
}
it("should split three lines", function() {
let lines = [];
let ls = createReverseSplitter(lines);
ls.write(Buffer.from("line 1\nline 2\nline 3\n"));
ls.end();
assert.deepEqual(lines, ["line 3", "line 2", "line 1"]);
});
it("should split three Windows line endings lines", function() {
let lines = [];
let ls = createReverseSplitter(lines);
ls.write(Buffer.from("line 1\r\nline 2\r\nline 3\r\n"));
ls.end();
assert.deepEqual(lines, ["line 3", "line 2", "line 1"]);
});
it("should handle mixed line endings", function() {
let lines = [];
let ls = createReverseSplitter(lines);
ls.write(Buffer.from("1\n\n2\r\n\r\n3\n4"));
ls.end();
assert.deepEqual(lines, ["4", "3", "", "2", "", "1"]);
});
it("should give the first line on .end()", function() {
let lines = [];
let ls = createReverseSplitter(lines);
ls.write(Buffer.from("line a\nline b"));
assert.deepEqual(lines, ["line b"]);
ls.end();
assert.deepEqual(lines, ["line b", "line a"]);
});
it("should handled partial lines", function() {
let lines = [];
let ls = createReverseSplitter(lines);
ls.write(Buffer.from("part 3\n"));
ls.write(Buffer.from(" part 2 "));
ls.write(Buffer.from("part 1"));
ls.end();
assert.deepEqual(lines, ["part 1 part 2 part 3"]);
});
});
describe("createReverseReadStream()", function() {
it("should read chunks in a file in reverse", async function() {
let content = "";
for (let i = 0; i < 10; i++) { content += String(i).repeat(10); }
await fs.outputFile(path.join("temp", "test", "reverse.txt"), content);
let reverseStream = await libStream.createReverseReadStream(
path.join("temp", "test", "reverse.txt"),
{ encoding: "utf8", highWaterMark: 10 }
);
let index = 9;
reverseStream.on("data", data => {
assert.equal(data, String(index).repeat(10));
index -= 1;
});
await finished(reverseStream);
});
it("should reverse the lines of a file", async function() {
let ws = fs.createWriteStream(path.join("temp", "test", "reverse.txt"));
for (let i = 1; i < 100000; i++) {
ws.write(Buffer.from(`${i}\n`));
}
ws.end();
await finished(ws);
let lineStream = new libStream.ReverseLineSplitter({ readableObjectMode: true });
let index = 99999;
let rs = await libStream.createReverseReadStream(path.join("temp", "test", "reverse.txt"));
lineStream.on("data", line => {
let n = Number(line.toString());
if (index !== n) {
rs.destroy();
assert.equal(n, index);
}
index -= 1;
});
rs.pipe(lineStream);
await finished(lineStream);
assert.equal(index, 0, "line check did not reach the end");
});
});
});