Skip to content

Commit

Permalink
fix(cli): Improve number parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
sirtimid committed Sep 20, 2024
1 parent 7948a69 commit 3b4a975
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 9 deletions.
9 changes: 6 additions & 3 deletions packages/cli/src/commands/adopt.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import os from 'os';
import { E } from '@endo/far';
import { withEndoAgent } from '../context.js';
import { parsePetNamePath } from '../pet-name.js';
import { parseNumber } from '../number-parse.js';

export const adoptCommand = async ({
messageNumberText,
Expand All @@ -11,7 +12,9 @@ export const adoptCommand = async ({
agentNames,
}) =>
withEndoAgent(agentNames, { os, process }, async ({ agent }) => {
// TODO less bad number parsing.
const messageNumber = Number(messageNumberText);
await E(agent).adopt(messageNumber, edgeName, parsePetNamePath(name));
await E(agent).adopt(
parseNumber(messageNumberText),
edgeName,
parsePetNamePath(name),
);
});
5 changes: 2 additions & 3 deletions packages/cli/src/commands/reject.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
import os from 'os';
import { E } from '@endo/far';
import { withEndoAgent } from '../context.js';
import { parseNumber } from '../number-parse.js';

export const rejectCommand = async ({
requestNumberText,
message,
agentNames,
}) =>
withEndoAgent(agentNames, { os, process }, async ({ agent }) => {
// TODO less bad number parsing.
const requestNumber = Number(requestNumberText);
await E(agent).reject(requestNumber, message);
await E(agent).reject(parseNumber(requestNumberText), message);
});
5 changes: 2 additions & 3 deletions packages/cli/src/commands/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
import os from 'os';
import { E } from '@endo/far';
import { withEndoAgent } from '../context.js';
import { parseNumber } from '../number-parse.js';

export const resolveCommand = async ({
requestNumberText,
resolutionName,
agentNames,
}) =>
withEndoAgent(agentNames, { os, process }, async ({ agent }) => {
// TODO less bad number parsing.
const requestNumber = Number(requestNumberText);
await E(agent).resolve(requestNumber, resolutionName);
await E(agent).resolve(parseNumber(requestNumberText), resolutionName);
});
15 changes: 15 additions & 0 deletions packages/cli/src/number-parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Parses the input and returns it as a number if it's valid, otherwise throws error.
*
* @param {string | number} input
* @returns {number | undefined}
*/
export const parseNumber = (input = '') => {
const result = /[0-9]/.test(input) ? Number(input) : NaN;

if (Number.isNaN(result)) {
throw new Error(`Invalid number: ${input}`);
}

return result;
};
67 changes: 67 additions & 0 deletions packages/cli/test/number-parse.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import test from 'ava';
import { parseNumber } from '../src/number-parse.js';

// Test for valid number input
test('returns the number itself if input is a valid number', t => {
t.is(parseNumber(42), 42);
t.is(parseNumber(-42), -42);
t.is(parseNumber(0), 0);
t.is(parseNumber(3.14), 3.14);
t.is(parseNumber(-3.14), -3.14);
});

// Test for valid string input (includes binary, octal and hexadecimal)
test('returns the number when input is a valid numeric string', t => {
t.is(parseNumber('42'), 42);
t.is(parseNumber('-40.0'), -40.0);
t.is(parseNumber('.5'), 0.5);
t.is(parseNumber('1.337e3'), 1337);
t.is(parseNumber(' +1 '), 1);
t.is(parseNumber('0B111'), 7);
t.is(parseNumber('0o040'), 32);
t.is(parseNumber('0xf00'), 3840);
t.is(parseNumber(' -40.0 '), -40.0);
// Test for binary, octal and hexadecimal
t.is(parseNumber('0B111'), 7);
t.is(parseNumber('0o040'), 32);
t.is(parseNumber('0xf00'), 3840);
});

// Test for invalid string input
test('throws an error when input is not a valid numeric string', t => {
const error = t.throws(() => parseNumber('f00'));
t.is(error.message, 'Invalid number: f00');

const error2 = t.throws(() => parseNumber('NaN'));
t.is(error2.message, 'Invalid number: NaN');

const error3 = t.throws(() => parseNumber('Infinity'));
t.is(error3.message, 'Invalid number: Infinity');

const error4 = t.throws(() => parseNumber('7up'));
t.is(error4.message, 'Invalid number: 7up');

const error5 = t.throws(() => parseNumber(' ')); // Unicode character
t.is(error5.message, 'Invalid number:  ');

const error6 = t.throws(() => parseNumber(''));
t.is(error6.message, 'Invalid number: ');

const error7 = t.throws(() => parseNumber(' '));
t.is(error7.message, 'Invalid number: ');
});

// Test for invalid input
test('throws an error when input is not a valid number', t => {
const error1 = t.throws(() => parseNumber(null));
t.is(error1.message, 'Invalid number: null');

const error2 = t.throws(() => parseNumber(undefined));
t.is(error2.message, 'Invalid number: ');

const error3 = t.throws(() => parseNumber({}));
t.is(error3.message, 'Invalid number: [object Object]');

const error4 = t.throws(() => parseNumber([]));
t.is(error4.message, 'Invalid number: ');
});

0 comments on commit 3b4a975

Please sign in to comment.