Skip to content

Commit

Permalink
Procedurally enforce JS formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
jugglinmike committed Jan 23, 2024
1 parent a54438f commit 81dee84
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 54 deletions.
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tabWidth": 2,
"useTabs": false,
"printWidth": 100,
"singleQuote": true,
"arrowParens": "avoid"
}
8 changes: 4 additions & 4 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ const DEFAULT_PORT = 4382;
*/
const log = (...args) => console.error(new Date().toISOString(), ...args);

module.exports = async (process) => {
module.exports = async process => {
const argv = yargs(hideBin(process.argv))
.option('port', {
coerce(string) {
if (!/^(0|[1-9][0-9]*)$/.test(string)) {
throw new TypeError(
`"port" option: expected a non-negative integer value but received "${string}"`
`"port" option: expected a non-negative integer value but received "${string}"`,
);
}
return Number(string);
Expand All @@ -42,11 +42,11 @@ module.exports = async (process) => {

log(`listening on port ${argv.port}`);

commandServer.on('error', (error) => {
commandServer.on('error', error => {
log(`error: ${error}`);
});

voiceServer.on('message', (message) => {
voiceServer.on('message', message => {
log(`voice server received message ${JSON.stringify(message)}`);
if (message.name == 'speech') {
commandServer.broadcast({
Expand Down
8 changes: 4 additions & 4 deletions lib/create-command-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ const sessionModule = require('./modules/session');

const broadcast = (server, message) => {
const packedMessage = JSON.stringify(message);
server.clients.forEach((websocket) => {
server.clients.forEach(websocket => {
if (websocket.sessionId) {
websocket.send(packedMessage, (error) => {
websocket.send(packedMessage, error => {
if (error) {
server.emit('error', `error sending message: ${error}`);
}
Expand All @@ -24,7 +24,7 @@ const methodHandlers = {
const onConnection = websocket => {
const send = value => websocket.send(JSON.stringify(value));

websocket.on('message', async (data) => {
websocket.on('message', async data => {
let parsed;
try {
parsed = JSON.parse(data);
Expand Down Expand Up @@ -87,7 +87,7 @@ module.exports = async function createWebSocketServer(port) {
path: '/session',
port,
});
await new Promise((resolve) => server.once('listening', resolve));
await new Promise(resolve => server.once('listening', resolve));

server.broadcast = broadcast.bind(null, server);
server.on('connection', onConnection);
Expand Down
8 changes: 4 additions & 4 deletions lib/create-voice-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ const net = require('net');

const onConnection = (server, socket) => {
let emitted = '';
socket.on('data', (buffer) => emitted += buffer.toString());
socket.on('data', buffer => (emitted += buffer.toString()));
socket.on('end', () => {
const match = emitted.match(/^(lifecycle|speech|internalError):(.*)$/);
const [name, data] = match ?
[match[1], match[2]] :
['internalError', `unrecognized message: "${emitted}"`];
const [name, data] = match
? [match[1], match[2]]
: ['internalError', `unrecognized message: "${emitted}"`];

server.emit('message', { type: 'event', name, data });
});
Expand Down
18 changes: 17 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"scripts": {
"postinstall": "Release\\MakeVoice.exe",
"postuninstall": "Release\\MakeVoice.exe /u",
"test": "mocha --ui tdd test"
"prettier": "prettier --write lib test",
"test": "prettier --check lib test && npm run test-unit",
"test-unit": "mocha --ui tdd test"
},
"files": [
"lib",
Expand All @@ -20,7 +22,8 @@
"author": "",
"license": "MIT",
"devDependencies": {
"mocha": "^9.1.2"
"mocha": "^9.1.2",
"prettier": "^3.2.4"
},
"dependencies": {
"robotjs": "^0.6.0",
Expand Down
83 changes: 44 additions & 39 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,37 @@ const net = require('net');
const WebSocket = require('ws');

const executable = path.join(__dirname, '..', 'bin', 'at-driver');
const invert = (promise) => promise.then(
() => { throw new Error('expected promise to be rejected, but it was fulfilled'); },
() => {}
);
const invert = promise =>
promise.then(
() => {
throw new Error('expected promise to be rejected, but it was fulfilled');
},
() => {},
);

suite('at-driver', () => {
const children = [];
const run = (args) => {
const run = args => {
const child = child_process.spawn(process.execPath, [executable, ...args]);
children.push(child);
const whenClosed = new Promise((resolve, reject) => {
child.on('error', reject);
child.on('close', () => reject(new Error('Server closed unexpectedly')));
});
return new Promise((resolve, reject) => {
child.stderr.on('data', () => resolve({whenClosed}));
child.stderr.on('data', () => resolve({ whenClosed }));
whenClosed.catch(reject);
});
};
const sendVoicePacket = async (type, data) => {
const NAMED_PIPE = '\\\\?\\pipe\\my_pipe';
const stream = await new Promise((resolve) => {
const stream = await new Promise(resolve => {
const stream = net.connect(NAMED_PIPE);
stream.on('connect', () => resolve(stream));
});
await new Promise(resolve => stream.end(`${type}:${data}`, 'utf8', resolve));

}
const connect = (port) => {
};
const connect = port => {
const websocket = new WebSocket(`ws://localhost:${port}/session`);

return new Promise((resolve, reject) => {
Expand All @@ -44,62 +46,62 @@ suite('at-driver', () => {
});
};
teardown(() => {
children.forEach((child) => child.kill());
children.forEach(child => child.kill());
children.length = 0;
});

test('WebSocket server on default port', async () => {
const {whenClosed} = await run([]);
const { whenClosed } = await run([]);
return Promise.race([whenClosed, connect(4382)]);
});

test('WebSocket server on custom port', async () => {
const {whenClosed} = await run(['--port', '6543']);
const { whenClosed } = await run(['--port', '6543']);
return Promise.race([whenClosed, connect(6543)]);
});

test('rejects invalid port values: unspecified', async () => {
const {whenClosed} = await run(['--port']);
const { whenClosed } = await run(['--port']);
return invert(whenClosed);
});

test('rejects invalid port values: non-numeric', async () => {
const {whenClosed} = await run(['--port', 'seven']);
const { whenClosed } = await run(['--port', 'seven']);
return invert(whenClosed);
});

test('rejects invalid port values: negative', async () => {
const {whenClosed} = await run(['--port', '-8000']);
const { whenClosed } = await run(['--port', '-8000']);
return invert(whenClosed);
});

test('rejects invalid port values: non-integer', async () => {
const {whenClosed} = await run(['--port', '2004.3']);
const { whenClosed } = await run(['--port', '2004.3']);
return invert(whenClosed);
});

test('rejects invalid port values: non-decimal', async () => {
const {whenClosed} = await run(['--port', '0x1000']);
const { whenClosed } = await run(['--port', '0x1000']);
return invert(whenClosed);
});

suite('protocol', () => {
let websocket, whenClosed;
const nextMessage = (websocket) => {
const nextMessage = websocket => {
return new Promise((resolve, reject) => {
websocket.once('message', (buffer) => {
try {
websocket.once('message', buffer => {
try {
resolve(JSON.parse(buffer.toString()));
} catch (error) {
} catch (error) {
reject(error);
}
}
});
websocket.once('error', reject);
});
};

setup(async () => {
({whenClosed} = await run([]));
({ whenClosed } = await run([]));

websocket = await Promise.race([whenClosed, connect(4382)]);
});
Expand All @@ -111,7 +113,7 @@ suite('at-driver', () => {
assert.deepEqual(message, {
id: null,
error: 'unknown error',
message: 'Unable to parse message: "not JSON".'
message: 'Unable to parse message: "not JSON".',
});
});

Expand All @@ -122,7 +124,7 @@ suite('at-driver', () => {
assert.deepEqual(message, {
id: null,
error: 'unknown error',
message: 'Malformed message: "[]".'
message: 'Malformed message: "[]".',
});
});

Expand All @@ -133,7 +135,7 @@ suite('at-driver', () => {
assert.deepEqual(message, {
id: null,
error: 'unknown command',
message: 'Unrecognized message type (no method): "{"id": 1, "type": "foobar"}".'
message: 'Unrecognized message type (no method): "{"id": 1, "type": "foobar"}".',
});
});

Expand All @@ -144,7 +146,8 @@ suite('at-driver', () => {
assert.deepEqual(message, {
id: null,
error: 'unknown error',
message: 'Command missing required "id": "{"method": "interaction.pressKeys", "params": {"keys": ["A"]}}".'
message:
'Command missing required "id": "{"method": "interaction.pressKeys", "params": {"keys": ["A"]}}".',
});
});

Expand All @@ -164,48 +167,50 @@ suite('at-driver', () => {

assert.deepEqual(message, {
id: 83,
result: {}
result: {},
});
});

test('rejects invalid "pressKey" Command', async () => {
websocket.send('{"id": 902, "method": "interaction.pressKeys", "params": {"keys": ["df daf% ?"]}}');
websocket.send(
'{"id": 902, "method": "interaction.pressKeys", "params": {"keys": ["df daf% ?"]}}',
);
const message = await Promise.race([whenClosed, nextMessage(websocket)]);

assert.deepEqual(message, {
id: 902,
error: 'unknown error',
message: 'Invalid key code specified.'
message: 'Invalid key code specified.',
});
});

suite('with sessionId', () => {
let sessionId, capabilities;
setup(async() => {
setup(async () => {
websocket.send('{"id": 527, "method": "session.new", "params": {}}');
const message = await Promise.race([whenClosed, nextMessage(websocket)]);

assert.ok(message.result);
sessionId = message.result.sessionId;
capabilities = message.result.capabilities;
})
});

test('returns a sessionId', () => {
assert.notEqual(sessionId, undefined);
})
});

test('sends voice events', async () => {
await Promise.race([whenClosed, sendVoicePacket('speech', 'Hello, world!')]);

const message = await Promise.race([whenClosed, nextMessage(websocket)]);

assert.deepEqual(message, {
method: "interaction.capturedOutput",
method: 'interaction.capturedOutput',
params: {
data: "Hello, world!"
}
data: 'Hello, world!',
},
});
})
})
});
});
});
});

0 comments on commit 81dee84

Please sign in to comment.