diff --git a/src/stdlib/__tests__/__snapshots__/misc.ts.snap b/src/stdlib/__tests__/__snapshots__/misc.ts.snap new file mode 100644 index 000000000..9dcc40e83 --- /dev/null +++ b/src/stdlib/__tests__/__snapshots__/misc.ts.snap @@ -0,0 +1,62 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`parse_int with non-integer arg radix throws error 1`] = ` +Object { + "status": "error", +} +`; + +exports[`parse_int with non-integer arg radix throws error 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`; + +exports[`parse_int with non-string arg str throws error 1`] = ` +Object { + "status": "error", +} +`; + +exports[`parse_int with non-string arg str throws error 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`; + +exports[`parse_int with radix outside [2, 36] throws error, radix=1 1`] = ` +Object { + "status": "error", +} +`; + +exports[`parse_int with radix outside [2, 36] throws error, radix=1 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`; + +exports[`parse_int with radix outside [2, 36] throws error, radix=37 1`] = ` +Object { + "status": "error", +} +`; + +exports[`parse_int with radix outside [2, 36] throws error, radix=37 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`; + +exports[`parse_int with string arg radix throws error 1`] = ` +Object { + "status": "error", +} +`; + +exports[`parse_int with string arg radix throws error 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`; + +exports[`parse_int with valid args is ok, but invalid str for radix 1`] = ` +Object { + "status": "finished", + "value": NaN, +} +`; + +exports[`parse_int with valid args is ok, radix 2 1`] = ` +Object { + "status": "finished", + "value": 6485, +} +`; + +exports[`parse_int with valid args is ok, radix 36 1`] = ` +Object { + "status": "finished", + "value": 39961, +} +`; diff --git a/src/stdlib/__tests__/misc.ts b/src/stdlib/__tests__/misc.ts new file mode 100644 index 000000000..496ba5abb --- /dev/null +++ b/src/stdlib/__tests__/misc.ts @@ -0,0 +1,112 @@ +import { mockContext } from "../../mocks/context" +import { parseError, runInContext } from "../../index" +import { Finished } from "../../types"; + +test("parse_int with valid args is ok, radix 2", () => { + const program = ` + parse_int('1100101010101', 2); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('finished') + expect((obj as Finished).value).toBe(parseInt('1100101010101', 2)) + }) +}) + +test("parse_int with valid args is ok, radix 36", () => { + const program = ` + parse_int('uu1', 36); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('finished') + expect((obj as Finished).value).toBe(parseInt('uu1', 36)) + }) +}) + +test("parse_int with valid args is ok, but invalid str for radix", () => { + const program = ` + parse_int('uu1', 2); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('finished') + expect((obj as Finished).value).toBe(parseInt('uu1', 2)) + }) +}) + +test("parse_int with non-string arg str throws error", () => { + const program = ` + parse_int(42, 2); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('error') + const errors = parseError(context.errors) + expect(errors).toMatchSnapshot() + }) +}) + +test("parse_int with non-integer arg radix throws error", () => { + const program = ` + parse_int(42, 2.1); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('error') + const errors = parseError(context.errors) + expect(errors).toMatchSnapshot() + }) +}) + +test("parse_int with radix outside [2, 36] throws error, radix=1", () => { + const program = ` + parse_int('10', 1); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('error') + const errors = parseError(context.errors) + expect(errors).toMatchSnapshot() + }) +}) + +test("parse_int with radix outside [2, 36] throws error, radix=37", () => { + const program = ` + parse_int('10', 37); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('error') + const errors = parseError(context.errors) + expect(errors).toMatchSnapshot() + }) +}) + +test("parse_int with string arg radix throws error", () => { + const program = ` + parse_int(42, '2'); + ` + const context = mockContext() + const promise = runInContext(program, context, { scheduler: "preemptive" }) + return promise.then(obj => { + expect(obj).toMatchSnapshot() + expect(obj.status).toBe('error') + const errors = parseError(context.errors) + expect(errors).toMatchSnapshot() + }) +}) diff --git a/src/stdlib/misc.ts b/src/stdlib/misc.ts index 536864d0d..6041dd1e2 100644 --- a/src/stdlib/misc.ts +++ b/src/stdlib/misc.ts @@ -43,13 +43,20 @@ export function array_length(xs: Value[]) { } array_length.__SOURCE__ = 'array_length(xs)' -export function parse_int(inputString: string, radix: number) { - const parsed = parseInt(inputString, radix) - if (inputString && radix && parsed) { - // the two arguments are provided, and parsed is not NaN - return parsed +/** + * Source version of parseInt. Both arguments are required. + * + * @param str String representation of the integer to be parsed. Required. + * @param radix Base to parse the given `str`. Required. + * + * An error is thrown if `str` is not of type string, or `radix` is not an + * integer within the range 2, 36 inclusive. + */ +export function parse_int(str: string, radix: number) { + if (typeof(str) === 'string' && typeof(radix) === 'number' && Number.isInteger(radix) && 2 <= radix && radix <= 36) { + return parseInt(str, radix) } else { - throw new Error('parse_int expects two arguments a string s, and a positive integer i') + throw new Error('parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive.') } } parse_int.__SOURCE__ = 'parse_int(s, i)'