Skip to content

Commit d3545d4

Browse files
committed
BREAKING: fs.read() & fs.write() should return objects
For forward-compat with util.promisify()
1 parent 15db64f commit d3545d4

File tree

3 files changed

+197
-2
lines changed

3 files changed

+197
-2
lines changed

lib/fs/__tests__/multi-param.test.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
'use strict'
2+
/* eslint-env mocha */
3+
const assert = require('assert')
4+
const path = require('path')
5+
const crypto = require('crypto')
6+
const os = require('os')
7+
const semver = require('semver')
8+
const fs = require('../..')
9+
10+
const SIZE = 1000
11+
12+
// Used for tests on Node 7.2.0+ only
13+
const onNode7it = semver.gte(process.version, '7.2.0') ? it : it.skip
14+
15+
describe('fs.read()', () => {
16+
let TEST_FILE
17+
let TEST_DATA
18+
let TEST_FD
19+
20+
beforeEach(() => {
21+
TEST_FILE = path.join(os.tmpdir(), 'fs-extra', 'read-test-file')
22+
TEST_DATA = crypto.randomBytes(SIZE)
23+
fs.writeFileSync(TEST_FILE, TEST_DATA)
24+
TEST_FD = fs.openSync(TEST_FILE, 'r')
25+
})
26+
27+
afterEach(() => {
28+
return fs.close(TEST_FD)
29+
.then(() => fs.remove(TEST_FILE))
30+
})
31+
32+
describe('with promises', () => {
33+
it('returns an object', () => {
34+
return fs.read(TEST_FD, Buffer.alloc(SIZE), 0, SIZE, 0)
35+
.then(results => {
36+
const bytesRead = results.bytesRead
37+
const buffer = results.buffer
38+
assert.equal(bytesRead, SIZE, 'bytesRead is correct')
39+
assert(buffer.equals(TEST_DATA), 'data is correct')
40+
})
41+
})
42+
43+
it('returns an object when position is not set', () => {
44+
return fs.read(TEST_FD, Buffer.alloc(SIZE), 0, SIZE)
45+
.then(results => {
46+
const bytesRead = results.bytesRead
47+
const buffer = results.buffer
48+
assert.equal(bytesRead, SIZE, 'bytesRead is correct')
49+
assert(buffer.equals(TEST_DATA), 'data is correct')
50+
})
51+
})
52+
})
53+
54+
describe('with callbacks', () => {
55+
it('works', done => {
56+
fs.read(TEST_FD, Buffer.alloc(SIZE), 0, SIZE, 0, (err, bytesRead, buffer) => {
57+
assert.ifError(err)
58+
assert.equal(bytesRead, SIZE, 'bytesRead is correct')
59+
assert(buffer.equals(TEST_DATA), 'data is correct')
60+
done()
61+
})
62+
})
63+
64+
it('works when position is null', done => {
65+
require('fs').read(TEST_FD, Buffer.alloc(SIZE), 0, SIZE, null, (err, bytesRead, buffer) => {
66+
assert.ifError(err)
67+
assert.equal(bytesRead, SIZE, 'bytesRead is correct')
68+
assert(buffer.equals(TEST_DATA), 'data is correct')
69+
done()
70+
})
71+
})
72+
})
73+
})
74+
75+
describe('fs.write()', () => {
76+
let TEST_FILE
77+
let TEST_DATA
78+
let TEST_FD
79+
80+
beforeEach(() => {
81+
TEST_FILE = path.join(os.tmpdir(), 'fs-extra', 'write-test-file')
82+
TEST_DATA = crypto.randomBytes(SIZE)
83+
fs.ensureDirSync(path.dirname(TEST_FILE))
84+
TEST_FD = fs.openSync(TEST_FILE, 'w')
85+
})
86+
87+
afterEach(() => {
88+
return fs.close(TEST_FD)
89+
.then(() => fs.remove(TEST_FILE))
90+
})
91+
92+
describe('with promises', () => {
93+
it('returns an object', () => {
94+
return fs.write(TEST_FD, TEST_DATA, 0, SIZE, 0)
95+
.then(results => {
96+
const bytesWritten = results.bytesWritten
97+
const buffer = results.buffer
98+
assert.equal(bytesWritten, SIZE, 'bytesWritten is correct')
99+
assert(buffer.equals(TEST_DATA), 'data is correct')
100+
})
101+
})
102+
103+
onNode7it('returns an object when minimal arguments are passed', () => {
104+
return fs.write(TEST_FD, TEST_DATA)
105+
.then(results => {
106+
const bytesWritten = results.bytesWritten
107+
const buffer = results.buffer
108+
assert.equal(bytesWritten, SIZE, 'bytesWritten is correct')
109+
assert(buffer.equals(TEST_DATA), 'data is correct')
110+
})
111+
})
112+
113+
it('returns an object when writing a string', () => {
114+
const message = 'Hello World!'
115+
return fs.write(TEST_FD, message)
116+
.then(results => {
117+
const bytesWritten = results.bytesWritten
118+
const buffer = results.buffer
119+
assert.equal(bytesWritten, message.length, 'bytesWritten is correct')
120+
assert.equal(buffer, message, 'data is correct')
121+
})
122+
})
123+
})
124+
125+
describe('with callbacks', () => {
126+
it('works', done => {
127+
fs.write(TEST_FD, TEST_DATA, 0, SIZE, 0, (err, bytesWritten, buffer) => {
128+
assert.ifError(err)
129+
assert.equal(bytesWritten, SIZE, 'bytesWritten is correct')
130+
assert(buffer.equals(TEST_DATA), 'data is correct')
131+
done()
132+
})
133+
})
134+
135+
onNode7it('works when minimal arguments are passed', done => {
136+
fs.write(TEST_FD, TEST_DATA, (err, bytesWritten, buffer) => {
137+
assert.ifError(err)
138+
assert.equal(bytesWritten, SIZE, 'bytesWritten is correct')
139+
assert(buffer.equals(TEST_DATA), 'data is correct')
140+
done()
141+
})
142+
})
143+
144+
it('works when writing a string', done => {
145+
const message = 'Hello World!'
146+
return fs.write(TEST_FD, message, (err, bytesWritten, buffer) => {
147+
assert.ifError(err)
148+
assert.equal(bytesWritten, message.length, 'bytesWritten is correct')
149+
assert.equal(buffer, message, 'data is correct')
150+
done()
151+
})
152+
})
153+
})
154+
})

lib/fs/index.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const api = [
2121
'lstat',
2222
'mkdir',
2323
'open',
24-
'read',
2524
'readFile',
2625
'readdir',
2726
'readlink',
@@ -33,7 +32,6 @@ const api = [
3332
'truncate',
3433
'unlink',
3534
'utimes',
36-
'write',
3735
'writeFile'
3836
]
3937
// fs.mkdtemp() was added in Node.js v5.10.0, so check if it exists
@@ -59,3 +57,45 @@ exports.exists = function (filename, callback) {
5957
return fs.exists(filename, resolve)
6058
})
6159
}
60+
61+
// fs.read() & fs.write need special treatment due to multiple callback args
62+
63+
exports.read = function (fd, buffer, offset, length, position, callback) {
64+
if (typeof callback === 'function') {
65+
return fs.read(fd, buffer, offset, length, position, callback)
66+
}
67+
return new Promise((resolve, reject) => {
68+
fs.read(fd, buffer, offset, length, position, (err, bytesRead, buffer) => {
69+
if (err) return reject(err)
70+
resolve({ bytesRead, buffer })
71+
})
72+
})
73+
}
74+
75+
// Function signature can be
76+
// fs.write(fd, buffer[, offset[, length[, position]]], callback)
77+
// OR
78+
// fs.write(fd, string[, position[, encoding]], callback)
79+
// so we need to handle both cases
80+
exports.write = function (fd, buffer, a, b, c, callback) {
81+
if (typeof arguments[arguments.length - 1] === 'function') {
82+
return fs.write(fd, buffer, a, b, c, callback)
83+
}
84+
85+
// Check for old, depricated fs.write(fd, string[, position[, encoding]], callback)
86+
if (typeof buffer === 'string') {
87+
return new Promise((resolve, reject) => {
88+
fs.write(fd, buffer, a, b, (err, bytesWritten, buffer) => {
89+
if (err) return reject(err)
90+
resolve({ bytesWritten, buffer })
91+
})
92+
})
93+
}
94+
95+
return new Promise((resolve, reject) => {
96+
fs.write(fd, buffer, a, b, c, (err, bytesWritten, buffer) => {
97+
if (err) return reject(err)
98+
resolve({ bytesWritten, buffer })
99+
})
100+
})
101+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"read-dir-files": "^0.1.1",
4949
"rimraf": "^2.2.8",
5050
"secure-random": "^1.1.1",
51+
"semver": "^5.3.0",
5152
"standard": "^10.0.2",
5253
"standard-markdown": "^2.3.0"
5354
},

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy