Skip to content

Commit e7bebba

Browse files
authored
Echo test mocks (shelljs#708)
* Add stdout/stderr test mocks * Mock stdout/stderr during echo tests * Fix lint issues * Use 'use strict' * Re-implement mocks as a prototype * Implement mocks as a single-instance * Remove redundant test * Create mocked stdout/stderr.write methods once
1 parent 7527b36 commit e7bebba

3 files changed

Lines changed: 147 additions & 90 deletions

File tree

src/echo.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ function _echo(opts) {
3333
try {
3434
options = common.parseOptions(messages[0], {
3535
'e': 'escapes',
36-
'n': 'no_newline'
36+
'n': 'no_newline',
3737
}, {
38-
silent: true
38+
silent: true,
3939
});
4040

4141
// Allow null to be echoed

test/echo.js

Lines changed: 101 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -2,137 +2,150 @@ import test from 'ava';
22

33
import shell from '..';
44
import utils from './utils/utils';
5+
import mocks from './utils/mocks';
56

67
shell.config.silent = true;
78

89
test.beforeEach(t => {
910
t.context.tmp = utils.getTempDir();
11+
mocks.init();
1012
});
1113

1214
test.afterEach.always(t => {
1315
shell.rm('-rf', t.context.tmp);
16+
mocks.restore();
1417
});
1518

1619
//
1720
// Valids
1821
//
1922

20-
test.cb('simple test with defaults', t => {
21-
const script = 'require(\'../global.js\'); echo("hello", "world");';
22-
utils.runScript(script, (err, stdout, stderr) => {
23-
t.falsy(err);
24-
t.is(stdout, 'hello world\n');
25-
t.is(stderr, '');
26-
t.end();
27-
});
23+
test('simple test with defaults', t => {
24+
const result = shell.echo('hello', 'world');
25+
const stdout = mocks.stdout();
26+
const stderr = mocks.stderr();
27+
t.falsy(shell.error());
28+
t.is(result.code, 0);
29+
t.is(stdout, 'hello world\n');
30+
t.is(stderr, '');
2831
});
2932

30-
test.cb('allow arguments to begin with a hyphen', t => {
33+
test('allow arguments to begin with a hyphen', t => {
3134
// see issue #20
32-
const script = 'require(\'../global.js\'); echo("-asdf", "111");';
33-
utils.runScript(script, (err, stdout, stderr) => {
34-
t.falsy(err);
35-
t.is(stdout, '-asdf 111\n');
36-
t.is(stderr, '');
37-
t.end();
38-
});
35+
const result = shell.echo('-asdf', '111');
36+
const stdout = mocks.stdout();
37+
const stderr = mocks.stderr();
38+
t.falsy(shell.error());
39+
t.is(result.code, 1);
40+
t.is(stdout, '-asdf 111\n');
41+
t.is(stderr, '');
3942
});
4043

41-
test.cb("using null as an explicit argument doesn't crash the function", t => {
42-
const script = 'require(\'../global.js\'); echo(null);';
43-
utils.runScript(script, (err, stdout, stderr) => {
44-
t.falsy(err);
45-
t.is(stdout, 'null\n');
46-
t.is(stderr, '');
47-
t.end();
48-
});
44+
test("using null as an explicit argument doesn't crash the function", t => {
45+
const result = shell.echo(null);
46+
const stdout = mocks.stdout();
47+
const stderr = mocks.stderr();
48+
t.falsy(shell.error());
49+
t.is(result.code, 0);
50+
t.is(stdout, 'null\n');
51+
t.is(stderr, '');
4952
});
5053

51-
test.cb('simple test with silent(true)', t => {
52-
const script = 'require(\'../global.js\'); config.silent=true; echo(555);';
53-
utils.runScript(script, (err, stdout) => {
54-
t.falsy(err);
55-
t.is(stdout, '555\n');
56-
t.end();
57-
});
54+
test('-e option', t => {
55+
const result = shell.echo('-e', '\tmessage');
56+
const stdout = mocks.stdout();
57+
const stderr = mocks.stderr();
58+
t.falsy(shell.error());
59+
t.is(result.code, 0);
60+
t.is(stdout, '\tmessage\n');
61+
t.is(stderr, '');
5862
});
5963

60-
test.cb('-e option', t => {
61-
const script = "require('../global.js'); echo('-e', '\\tmessage');";
62-
utils.runScript(script, (err, stdout) => {
63-
t.falsy(err);
64-
t.is(stdout, '\tmessage\n');
65-
t.end();
66-
});
67-
});
68-
69-
test.cb('piping to a file', t => {
64+
test('piping to a file', t => {
7065
// see issue #476
7166
shell.mkdir(t.context.tmp);
7267
const tmp = `${t.context.tmp}/echo.txt`;
73-
const script = `require('../global.js'); echo('A').toEnd('${tmp}'); echo('B').toEnd('${tmp}');`;
74-
utils.runScript(script, (err, stdout) => {
75-
const result = shell.cat(tmp);
76-
t.falsy(err);
77-
t.is(stdout, 'A\nB\n');
78-
t.is(result.toString(), 'A\nB\n');
79-
t.end();
80-
});
68+
const resultA = shell.echo('A').toEnd(tmp);
69+
t.falsy(shell.error());
70+
t.is(resultA.code, 0);
71+
const resultB = shell.echo('B').toEnd(tmp);
72+
t.falsy(shell.error());
73+
t.is(resultB.code, 0);
74+
const result = shell.cat(tmp);
75+
const stdout = mocks.stdout();
76+
const stderr = mocks.stderr();
77+
t.falsy(shell.error());
78+
t.is(stdout, 'A\nB\n');
79+
t.is(stderr, '');
80+
t.is(result.toString(), 'A\nB\n');
8181
});
8282

83-
test.cb('-n option', t => {
84-
const script = "require('../global.js'); echo('-n', 'message');";
85-
utils.runScript(script, (err, stdout) => {
86-
t.falsy(err);
87-
t.is(stdout, 'message');
88-
t.end();
89-
});
83+
test('-n option', t => {
84+
const result = shell.echo('-n', 'message');
85+
const stdout = mocks.stdout();
86+
const stderr = mocks.stderr();
87+
t.falsy(shell.error());
88+
t.is(result.code, 0);
89+
t.is(stdout, 'message');
90+
t.is(stderr, '');
9091
});
9192

92-
test.cb('-ne option', t => {
93-
const script = "require('../global.js'); echo('-ne', 'message');";
94-
utils.runScript(script, (err, stdout) => {
95-
t.falsy(err);
96-
t.is(stdout, 'message');
97-
t.end();
98-
});
93+
test('-ne option', t => {
94+
const result = shell.echo('-ne', 'message');
95+
const stdout = mocks.stdout();
96+
const stderr = mocks.stderr();
97+
t.falsy(shell.error());
98+
t.is(result.code, 0);
99+
t.is(stdout, 'message');
100+
t.is(stderr, '');
99101
});
100102

101-
test.cb('-en option', t => {
102-
const script = "require('../global.js'); echo('-en', 'message');";
103-
utils.runScript(script, (err, stdout) => {
104-
t.falsy(err);
105-
t.is(stdout, 'message');
106-
t.end();
107-
});
103+
test('-en option', t => {
104+
const result = shell.echo('-en', 'message');
105+
const stdout = mocks.stdout();
106+
const stderr = mocks.stderr();
107+
t.falsy(shell.error());
108+
t.is(result.code, 0);
109+
t.is(stdout, 'message');
110+
t.is(stderr, '');
108111
});
109112

110-
test.cb('-en option with escaped characters', t => {
111-
const script = "require('../global.js'); echo('-en', '\\tmessage\\n');";
112-
utils.runScript(script, (err, stdout) => {
113-
t.falsy(err);
114-
t.is(stdout, '\tmessage\n');
115-
t.end();
116-
});
113+
test('-en option with escaped characters', t => {
114+
const result = shell.echo('-en', '\tmessage\n');
115+
const stdout = mocks.stdout();
116+
const stderr = mocks.stderr();
117+
t.falsy(shell.error());
118+
t.is(result.code, 0);
119+
t.is(stdout, '\tmessage\n');
120+
t.is(stderr, '');
117121
});
118122

119-
test.cb('piping to a file with -n', t => {
123+
test('piping to a file with -n', t => {
120124
// see issue #476
121125
shell.mkdir(t.context.tmp);
122126
const tmp = `${t.context.tmp}/echo.txt`;
123-
const script = `require('../global.js'); echo('-n', 'A').toEnd('${tmp}'); echo('-n', 'B').toEnd('${tmp}');`;
124-
utils.runScript(script, (err, stdout) => {
125-
const result = shell.cat(tmp);
126-
t.falsy(err);
127-
t.is(stdout, 'AB');
128-
t.is(result.toString(), 'AB');
129-
t.end();
130-
});
127+
const resultA = shell.echo('-n', 'A').toEnd(tmp);
128+
t.falsy(shell.error());
129+
t.is(resultA.code, 0);
130+
const resultB = shell.echo('-n', 'B').toEnd(tmp);
131+
t.falsy(shell.error());
132+
t.is(resultB.code, 0);
133+
const result = shell.cat(tmp);
134+
const stdout = mocks.stdout();
135+
const stderr = mocks.stderr();
136+
t.falsy(shell.error());
137+
t.is(stdout, 'AB');
138+
t.is(stderr, '');
139+
t.is(result.toString(), 'AB');
131140
});
132141

133142
test('stderr with unrecognized options is empty', t => {
134-
// TODO: console output here needs to be muted
135143
const result = shell.echo('-asdf');
144+
const stdout = mocks.stdout();
145+
const stderr = mocks.stderr();
146+
t.falsy(shell.error());
147+
t.is(result.code, 1);
136148
t.falsy(result.stderr);
137-
t.is(result.stdout, '-asdf\n');
149+
t.is(stdout, '-asdf\n');
150+
t.is(stderr, '');
138151
});

test/utils/mocks.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
function addToString(str, val) {
2+
if (Buffer.isBuffer(val)) {
3+
return str + val.toString();
4+
}
5+
return str + val;
6+
}
7+
8+
function joinData(data) {
9+
return data.reduce(addToString, '');
10+
}
11+
12+
function wrapWrite(target) {
13+
return function write(val) {
14+
target.push(val);
15+
return true;
16+
};
17+
}
18+
19+
const _processStdoutWrite = process.stdout.write;
20+
const _processStderrWrite = process.stderr.write;
21+
const _stdout = [];
22+
const _stderr = [];
23+
const _stdoutWrite = wrapWrite(_stdout);
24+
const _stderrWrite = wrapWrite(_stderr);
25+
26+
exports.stdout = function stdout() {
27+
return joinData(_stdout);
28+
};
29+
30+
exports.stderr = function stderr() {
31+
return joinData(_stderr);
32+
};
33+
34+
exports.init = function init() {
35+
process.stdout.write = _stdoutWrite;
36+
process.stderr.write = _stderrWrite;
37+
};
38+
39+
exports.restore = function restore() {
40+
process.stdout.write = _processStdoutWrite;
41+
process.stderr.write = _processStderrWrite;
42+
_stdout.splice(0);
43+
_stderr.splice(0);
44+
};

0 commit comments

Comments
 (0)