1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-02 17:01:14 -05:00

Add bufio tests.

This commit is contained in:
Ryan Dahl 2018-11-07 20:28:01 -05:00
parent be1eb62bdc
commit aa9e3df0d2
3 changed files with 132 additions and 18 deletions

View file

@ -24,6 +24,7 @@ export class Reader implements deno.Reader {
private w = 0; // buf write position.
private lastByte: number;
private lastCharSize: number;
private err: null | Error;
constructor(rd: deno.Reader, size = DEFAULT_BUF_SIZE) {
if (size < MIN_BUF_SIZE) {
@ -37,9 +38,15 @@ export class Reader implements deno.Reader {
return this.buf.byteLength;
}
private _readErr(): Error {
const err = this.err;
this.err = null;
return err;
}
// Reads a new chunk into the buffer.
// Returns true if EOF, false on successful read.
async _fill(): Promise<boolean> {
private async _fill(): Promise<boolean> {
// Slide existing data to beginning.
if (this.r > 0) {
this.buf.copyWithin(0, this.r, this.w);
@ -53,15 +60,21 @@ export class Reader implements deno.Reader {
// Read new data: try a limited number of times.
for (let i = MAX_CONSECUTIVE_EMPTY_READS; i > 0; i--) {
const { nread, eof } = await this.rd.read(this.buf.subarray(this.w));
if (nread < 0) {
let rr: deno.ReadResult;
try {
rr = await this.rd.read(this.buf.subarray(this.w));
} catch (e) {
this.err = e;
return false;
}
if (rr.nread < 0) {
throw new ErrNegativeRead();
}
this.w += nread;
if (eof) {
this.w += rr.nread;
if (rr.eof) {
return true;
}
if (nread > 0) {
if (rr.nread > 0) {
return false;
}
}
@ -92,15 +105,16 @@ export class Reader implements deno.Reader {
async read(p: ArrayBufferView): Promise<deno.ReadResult> {
let rr: deno.ReadResult = { nread: p.byteLength, eof: false };
if (rr.nread === 0) {
if (this.err) {
throw this._readErr();
}
return rr;
}
if (this.r === this.w) {
/*
if (this.err != null) {
throw this.readErr();
if (this.err) {
throw this._readErr();
}
*/
if (p.byteLength >= this.buf.byteLength) {
// Large read, empty buffer.
// Read directly into p to avoid copy.
@ -112,6 +126,9 @@ export class Reader implements deno.Reader {
this.lastByte = p[rr.nread - 1];
// this.lastRuneSize = -1;
}
if (this.err) {
throw this._readErr();
}
return rr;
}
// One read.
@ -123,6 +140,9 @@ export class Reader implements deno.Reader {
throw new ErrNegativeRead();
}
if (rr.nread === 0) {
if (this.err) {
throw this._readErr();
}
return rr;
}
this.w += rr.nread;
@ -140,6 +160,9 @@ export class Reader implements deno.Reader {
async readByte(): Promise<number> {
while (this.r === this.w) {
const eof = await this._fill(); // buffer is empty.
if (this.err != null) {
throw this._readErr();
}
if (eof) {
return -1;
}
@ -149,4 +172,16 @@ export class Reader implements deno.Reader {
this.lastByte = c;
return c;
}
/** readString() reads until the first occurrence of delim in the input,
* returning a string containing the data up to and including the delimiter.
* If ReadString encounters an error before finding a delimiter,
* it returns the data read before the error and the error itself (often io.EOF).
* ReadString returns err != nil if and only if the returned data does not end in
* delim.
* For simple uses, a Scanner may be more convenient.
*/
async readString(delim: string): Promise<string> {
throw new Error("Not implemented");
}
}

View file

@ -7,6 +7,7 @@ import * as deno from "deno";
import { test, assertEqual } from "http://deno.land/x/testing/testing.ts";
import * as bufio from "./bufio.ts";
import { Buffer } from "./buffer.ts";
import * as iotest from "./iotest.ts";
async function readBytes(buf: bufio.Reader): Promise<string> {
const b = new Uint8Array(1000);
@ -39,15 +40,25 @@ test(async function bufioReaderSimple() {
type ReadMaker = { name: string; fn: (r: deno.Reader) => deno.Reader };
const readMakers: ReadMaker[] = [
{ name: "full", fn: r => r }
/*
{ name: "byte", fn(r) => new iotest.OneByteReader(r) },
{ name: "half", fn(r) => new iotest.HalfReader(r) },
{ name: "data+err", r => new iotest.DataErrReader(r) },
{ name: "timeout", r => new iotest.TimeoutReader(r) },
*/
{ name: "full", fn: r => r },
{ name: "byte", fn: r => new iotest.OneByteReader(r) },
{ name: "half", fn: r => new iotest.HalfReader(r) }
// TODO { name: "data+err", r => new iotest.DataErrReader(r) },
// { name: "timeout", fn: r => new iotest.TimeoutReader(r) },
];
function readLines(b: bufio.Reader): string {
let s = "";
while (true) {
let s1 = b.readString("\n");
if (s1 == null) {
break; // EOF
}
s += s1;
}
return s;
}
// Call read to accumulate the text of a file
async function reads(buf: bufio.Reader, m: number): Promise<string> {
const b = new Uint8Array(1000);
@ -66,7 +77,14 @@ async function reads(buf: bufio.Reader, m: number): Promise<string> {
type BufReader = { name: string; fn: (r: bufio.Reader) => Promise<string> };
const bufreaders: BufReader[] = [
{ name: "1", fn: (b: bufio.Reader) => reads(b, 1) }
{ name: "1", fn: (b: bufio.Reader) => reads(b, 1) },
{ name: "2", fn: (b: bufio.Reader) => reads(b, 2) },
{ name: "3", fn: (b: bufio.Reader) => reads(b, 3) },
{ name: "4", fn: (b: bufio.Reader) => reads(b, 4) },
{ name: "5", fn: (b: bufio.Reader) => reads(b, 5) },
{ name: "7", fn: (b: bufio.Reader) => reads(b, 7) },
{ name: "bytes", fn: readBytes }
// { name: "lines", fn: readLines },
];
const MIN_READ_BUFFER_SIZE = 16;

61
iotest.ts Normal file
View file

@ -0,0 +1,61 @@
// Ported to Deno from
// Copyright 2009 The Go 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 { Reader, ReadResult } from "deno";
/** OneByteReader returns a Reader that implements
* each non-empty Read by reading one byte from r.
*/
export class OneByteReader implements Reader {
constructor(readonly r: Reader) {}
async read(p: ArrayBufferView): Promise<ReadResult> {
if (p.byteLength === 0) {
return { nread: 0, eof: false };
}
if (!(p instanceof Uint8Array)) {
throw Error("expected Uint8Array");
}
return this.r.read(p.subarray(0, 1));
}
}
/** HalfReader returns a Reader that implements Read
* by reading half as many requested bytes from r.
*/
export class HalfReader implements Reader {
constructor(readonly r: Reader) {}
async read(p: ArrayBufferView): Promise<ReadResult> {
if (!(p instanceof Uint8Array)) {
throw Error("expected Uint8Array");
}
const half = Math.floor((p.byteLength + 1) / 2);
return this.r.read(p.subarray(0, half));
}
}
export class ErrTimeout extends Error {
constructor() {
super("timeout");
this.name = "ErrTimeout";
}
}
/** TimeoutReader returns ErrTimeout on the second read
* with no data. Subsequent calls to read succeed.
*/
export class TimeoutReader implements Reader {
count = 0;
constructor(readonly r: Reader) {}
async read(p: ArrayBufferView): Promise<ReadResult> {
this.count++;
if (this.count === 2) {
throw new ErrTimeout();
}
return this.r.read(p);
}
}