mirror of
https://github.com/denoland/deno.git
synced 2024-12-03 17:08:35 -05:00
First pass at bufio.read tests.
This commit is contained in:
parent
c5cc695970
commit
1eb57aa394
7 changed files with 170 additions and 28 deletions
14
buffer.ts
14
buffer.ts
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//import * as io from "./io";
|
//import * as io from "./io";
|
||||||
import { Reader, Writer, ReadResult } from "deno";
|
import { Reader, Writer, ReadResult } from "deno";
|
||||||
import { assert } from "./util.ts";
|
import { assert, copyBytes } from "./util.ts";
|
||||||
|
|
||||||
// MIN_READ is the minimum ArrayBuffer size passed to a read call by
|
// MIN_READ is the minimum ArrayBuffer size passed to a read call by
|
||||||
// buffer.ReadFrom. As long as the Buffer has at least MIN_READ bytes beyond
|
// buffer.ReadFrom. As long as the Buffer has at least MIN_READ bytes beyond
|
||||||
|
@ -13,18 +13,6 @@ import { assert } from "./util.ts";
|
||||||
const MIN_READ = 512;
|
const MIN_READ = 512;
|
||||||
const MAX_SIZE = 2 ** 32 - 2;
|
const MAX_SIZE = 2 ** 32 - 2;
|
||||||
|
|
||||||
// `off` is the offset into `dst` where it will at which to begin writing values
|
|
||||||
// from `src`.
|
|
||||||
// Returns the number of bytes copied.
|
|
||||||
function copyBytes(dst: Uint8Array, src: Uint8Array, off = 0): number {
|
|
||||||
const r = dst.byteLength - off;
|
|
||||||
if (src.byteLength > r) {
|
|
||||||
src = src.subarray(0, r);
|
|
||||||
}
|
|
||||||
dst.set(src, off);
|
|
||||||
return src.byteLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A Buffer is a variable-sized buffer of bytes with read() and write()
|
/** A Buffer is a variable-sized buffer of bytes with read() and write()
|
||||||
* methods. Based on https://golang.org/pkg/bytes/#Buffer
|
* methods. Based on https://golang.org/pkg/bytes/#Buffer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
// This code has been ported almost directly from Go's src/bytes/buffer_test.go
|
// This code has been ported almost directly from Go's src/bytes/buffer_test.go
|
||||||
// Copyright 2009 The Go Authors. All rights reserved. BSD license.
|
// Copyright 2009 The Go Authors. All rights reserved. BSD license.
|
||||||
// https://github.com/golang/go/blob/master/LICENSE
|
// https://github.com/golang/go/blob/master/LICENSE
|
||||||
import { test, assert, assertEqual } from "./test_util.ts";
|
import {
|
||||||
import { Buffer } from "deno";
|
test,
|
||||||
|
assert,
|
||||||
|
assertEqual
|
||||||
|
} from "http://deno.land/x/testing/testing.ts";
|
||||||
|
import { Buffer } from "./buffer.ts";
|
||||||
|
|
||||||
// N controls how many iterations of certain checks are performed.
|
// N controls how many iterations of certain checks are performed.
|
||||||
const N = 100;
|
const N = 100;
|
||||||
|
@ -13,7 +17,7 @@ function init() {
|
||||||
if (testBytes == null) {
|
if (testBytes == null) {
|
||||||
testBytes = new Uint8Array(N);
|
testBytes = new Uint8Array(N);
|
||||||
for (let i = 0; i < N; i++) {
|
for (let i = 0; i < N; i++) {
|
||||||
testBytes[i] = "a".charCodeAt(0) + (i % 26);
|
testBytes[i] = "a".charCodeAt(0) + i % 26;
|
||||||
}
|
}
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
testString = decoder.decode(testBytes);
|
testString = decoder.decode(testBytes);
|
||||||
|
|
72
bufio.ts
72
bufio.ts
|
@ -1,9 +1,22 @@
|
||||||
|
// 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 * as deno from "deno";
|
import * as deno from "deno";
|
||||||
|
import { assert, copyBytes } from "./util.ts";
|
||||||
|
|
||||||
const DEFAULT_BUF_SIZE = 4096;
|
const DEFAULT_BUF_SIZE = 4096;
|
||||||
const MIN_BUF_SIZE = 16;
|
const MIN_BUF_SIZE = 16;
|
||||||
const MAX_CONSECUTIVE_EMPTY_READS = 100;
|
const MAX_CONSECUTIVE_EMPTY_READS = 100;
|
||||||
|
|
||||||
|
export class ErrNegativeRead extends Error {
|
||||||
|
constructor() {
|
||||||
|
super("bufio: reader returned negative count from Read");
|
||||||
|
this.name = "ErrNegativeRead";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Reader implements deno.Reader {
|
export class Reader implements deno.Reader {
|
||||||
private buf: Uint8Array;
|
private buf: Uint8Array;
|
||||||
private rd: deno.Reader; // Reader provided by caller.
|
private rd: deno.Reader; // Reader provided by caller.
|
||||||
|
@ -16,7 +29,7 @@ export class Reader implements deno.Reader {
|
||||||
if (size < MIN_BUF_SIZE) {
|
if (size < MIN_BUF_SIZE) {
|
||||||
size = MIN_BUF_SIZE;
|
size = MIN_BUF_SIZE;
|
||||||
}
|
}
|
||||||
this._reset(new Uint8Array(size), rd)
|
this._reset(new Uint8Array(size), rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the size of the underlying buffer in bytes. */
|
/** Returns the size of the underlying buffer in bytes. */
|
||||||
|
@ -42,7 +55,7 @@ export class Reader implements deno.Reader {
|
||||||
for (let i = MAX_CONSECUTIVE_EMPTY_READS; i > 0; i--) {
|
for (let i = MAX_CONSECUTIVE_EMPTY_READS; i > 0; i--) {
|
||||||
const { nread, eof } = await this.rd.read(this.buf.subarray(this.w));
|
const { nread, eof } = await this.rd.read(this.buf.subarray(this.w));
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
throw Error("negative read");
|
throw new ErrNegativeRead();
|
||||||
}
|
}
|
||||||
this.w += nread;
|
this.w += nread;
|
||||||
if (eof) {
|
if (eof) {
|
||||||
|
@ -69,9 +82,58 @@ export class Reader implements deno.Reader {
|
||||||
this.lastCharSize = -1;
|
this.lastCharSize = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** reads data into p.
|
||||||
|
* It returns the number of bytes read into p.
|
||||||
|
* The bytes are taken from at most one Read on the underlying Reader,
|
||||||
|
* hence n may be less than len(p).
|
||||||
|
* At EOF, the count will be zero and err will be io.EOF.
|
||||||
|
* To read exactly len(p) bytes, use io.ReadFull(b, p).
|
||||||
|
*/
|
||||||
async read(p: ArrayBufferView): Promise<deno.ReadResult> {
|
async read(p: ArrayBufferView): Promise<deno.ReadResult> {
|
||||||
throw Error("not implemented");
|
let rr: deno.ReadResult = { nread: p.byteLength, eof: false };
|
||||||
return { nread: 0, eof: false };
|
if (rr.nread === 0) {
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.r === this.w) {
|
||||||
|
/*
|
||||||
|
if (this.err != null) {
|
||||||
|
throw this.readErr();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (p.byteLength >= this.buf.byteLength) {
|
||||||
|
// Large read, empty buffer.
|
||||||
|
// Read directly into p to avoid copy.
|
||||||
|
rr = await this.rd.read(p);
|
||||||
|
if (rr.nread < 0) {
|
||||||
|
throw new ErrNegativeRead();
|
||||||
|
}
|
||||||
|
if (rr.nread > 0) {
|
||||||
|
this.lastByte = p[rr.nread - 1];
|
||||||
|
// this.lastRuneSize = -1;
|
||||||
|
}
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
// One read.
|
||||||
|
// Do not use this.fill, which will loop.
|
||||||
|
this.r = 0;
|
||||||
|
this.w = 0;
|
||||||
|
rr = await this.rd.read(this.buf);
|
||||||
|
if (rr.nread < 0) {
|
||||||
|
throw new ErrNegativeRead();
|
||||||
|
}
|
||||||
|
if (rr.nread === 0) {
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
this.w += rr.nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy as much as we can
|
||||||
|
rr.nread = copyBytes(p as Uint8Array, this.buf.subarray(this.r, this.w), 0);
|
||||||
|
this.r += rr.nread;
|
||||||
|
this.lastByte = this.buf[this.r - 1];
|
||||||
|
// this.lastRuneSize = -1;
|
||||||
|
return rr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the next byte [0, 255] or -1 if EOF. */
|
/** Returns the next byte [0, 255] or -1 if EOF. */
|
||||||
|
@ -88,5 +150,3 @@ export class Reader implements deno.Reader {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
// 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 * as deno from "deno";
|
import * as deno from "deno";
|
||||||
import { test, assertEqual } from "http://deno.land/x/testing/testing.ts";
|
import { test, assertEqual } from "http://deno.land/x/testing/testing.ts";
|
||||||
import * as bufio from "./bufio.ts";
|
import * as bufio from "./bufio.ts";
|
||||||
|
@ -30,3 +35,78 @@ test(async function bufioReaderSimple() {
|
||||||
const s = await readBytes(b);
|
const s = await readBytes(b);
|
||||||
assertEqual(s, data);
|
assertEqual(s, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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) },
|
||||||
|
*/
|
||||||
|
];
|
||||||
|
|
||||||
|
// Call read to accumulate the text of a file
|
||||||
|
async function reads(buf: bufio.Reader, m: number): Promise<string> {
|
||||||
|
const b = new Uint8Array(1000);
|
||||||
|
let nb = 0;
|
||||||
|
while (true) {
|
||||||
|
const { nread, eof } = await buf.read(b.subarray(nb, nb + m));
|
||||||
|
nb += nread;
|
||||||
|
if (eof) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
return decoder.decode(b.subarray(0, nb));
|
||||||
|
}
|
||||||
|
|
||||||
|
type BufReader = { name: string; fn: (r: bufio.Reader) => Promise<string> };
|
||||||
|
|
||||||
|
const bufreaders: BufReader[] = [
|
||||||
|
{ name: "1", fn: (b: bufio.Reader) => reads(b, 1) }
|
||||||
|
];
|
||||||
|
|
||||||
|
const MIN_READ_BUFFER_SIZE = 16;
|
||||||
|
const bufsizes: number[] = [
|
||||||
|
0,
|
||||||
|
MIN_READ_BUFFER_SIZE,
|
||||||
|
23,
|
||||||
|
32,
|
||||||
|
46,
|
||||||
|
64,
|
||||||
|
93,
|
||||||
|
128,
|
||||||
|
1024,
|
||||||
|
4096
|
||||||
|
];
|
||||||
|
|
||||||
|
test(async function bufioReader() {
|
||||||
|
const texts = new Array<string>(31);
|
||||||
|
let str = "";
|
||||||
|
let all = "";
|
||||||
|
for (let i = 0; i < texts.length - 1; i++) {
|
||||||
|
texts[i] = str + "\n";
|
||||||
|
all += texts[i];
|
||||||
|
str += String.fromCharCode(i % 26 + 97);
|
||||||
|
}
|
||||||
|
texts[texts.length - 1] = all;
|
||||||
|
|
||||||
|
for (let text of texts) {
|
||||||
|
for (let readmaker of readMakers) {
|
||||||
|
for (let bufreader of bufreaders) {
|
||||||
|
for (let bufsize of bufsizes) {
|
||||||
|
const read = readmaker.fn(stringsReader(text));
|
||||||
|
const buf = new bufio.Reader(read, bufsize);
|
||||||
|
const s = await bufreader.fn(buf);
|
||||||
|
const debugStr =
|
||||||
|
`reader=${readmaker.name} ` +
|
||||||
|
`fn=${bufreader.name} bufsize=${bufsize} want=${text} got=${s}`;
|
||||||
|
assertEqual(s, text, debugStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -4,12 +4,12 @@ import { open, cwd } from "deno";
|
||||||
const addr = "0.0.0.0:4500";
|
const addr = "0.0.0.0:4500";
|
||||||
const d = cwd();
|
const d = cwd();
|
||||||
|
|
||||||
listenAndServe(addr, async (req) => {
|
listenAndServe(addr, async req => {
|
||||||
const filename = d + "/" + req.url;
|
const filename = d + "/" + req.url;
|
||||||
let res;
|
let res;
|
||||||
try {
|
try {
|
||||||
res = { status: 200, body: open(filename) };
|
res = { status: 200, body: open(filename) };
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
res = { status: 500, body: "bad" };
|
res = { status: 500, body: "bad" };
|
||||||
}
|
}
|
||||||
req.respond(res);
|
req.respond(res);
|
||||||
|
|
5
http.ts
5
http.ts
|
@ -55,12 +55,12 @@ function readRequest(b: bufio.Reader): ServerRequest {
|
||||||
|
|
||||||
// First line: GET /index.html HTTP/1.0
|
// First line: GET /index.html HTTP/1.0
|
||||||
const s = await tp.readLine();
|
const s = await tp.readLine();
|
||||||
const [ method, url, proto ] = parseRequestLine(s);
|
const [method, url, proto] = parseRequestLine(s);
|
||||||
console.log("readRequest", method, url);
|
console.log("readRequest", method, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns [method, url, proto]
|
// Returns [method, url, proto]
|
||||||
function parseRequestLine(line: string): [ string, string, string ] {
|
function parseRequestLine(line: string): [string, string, string] {
|
||||||
return line.split(" ", 3);
|
return line.split(" ", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,4 +69,3 @@ export function listen(addr: string): Server {
|
||||||
const s = new Server(listener);
|
const s = new Server(listener);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
util.ts
13
util.ts
|
@ -1,6 +1,17 @@
|
||||||
|
|
||||||
export function assert(cond: boolean, msg = "assert") {
|
export function assert(cond: boolean, msg = "assert") {
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
throw Error(msg);
|
throw Error(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `off` is the offset into `dst` where it will at which to begin writing values
|
||||||
|
// from `src`.
|
||||||
|
// Returns the number of bytes copied.
|
||||||
|
export function copyBytes(dst: Uint8Array, src: Uint8Array, off = 0): number {
|
||||||
|
const r = dst.byteLength - off;
|
||||||
|
if (src.byteLength > r) {
|
||||||
|
src = src.subarray(0, r);
|
||||||
|
}
|
||||||
|
dst.set(src, off);
|
||||||
|
return src.byteLength;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue