Skip to content

Commit 462b050

Browse files
ning-ymartin-henz
authored andcommitted
Restrict parse_int radix to [2, 36] (#82)
* Restrict parse_int radix to [2, 36] * Add to JSdocs * Add tests for parse_int * Fix type errors
1 parent 615fb51 commit 462b050

File tree

3 files changed

+187
-6
lines changed

3 files changed

+187
-6
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`parse_int with non-integer arg radix throws error 1`] = `
4+
Object {
5+
"status": "error",
6+
}
7+
`;
8+
9+
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."`;
10+
11+
exports[`parse_int with non-string arg str throws error 1`] = `
12+
Object {
13+
"status": "error",
14+
}
15+
`;
16+
17+
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."`;
18+
19+
exports[`parse_int with radix outside [2, 36] throws error, radix=1 1`] = `
20+
Object {
21+
"status": "error",
22+
}
23+
`;
24+
25+
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."`;
26+
27+
exports[`parse_int with radix outside [2, 36] throws error, radix=37 1`] = `
28+
Object {
29+
"status": "error",
30+
}
31+
`;
32+
33+
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."`;
34+
35+
exports[`parse_int with string arg radix throws error 1`] = `
36+
Object {
37+
"status": "error",
38+
}
39+
`;
40+
41+
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."`;
42+
43+
exports[`parse_int with valid args is ok, but invalid str for radix 1`] = `
44+
Object {
45+
"status": "finished",
46+
"value": NaN,
47+
}
48+
`;
49+
50+
exports[`parse_int with valid args is ok, radix 2 1`] = `
51+
Object {
52+
"status": "finished",
53+
"value": 6485,
54+
}
55+
`;
56+
57+
exports[`parse_int with valid args is ok, radix 36 1`] = `
58+
Object {
59+
"status": "finished",
60+
"value": 39961,
61+
}
62+
`;

src/stdlib/__tests__/misc.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { mockContext } from "../../mocks/context"
2+
import { parseError, runInContext } from "../../index"
3+
import { Finished } from "../../types";
4+
5+
test("parse_int with valid args is ok, radix 2", () => {
6+
const program = `
7+
parse_int('1100101010101', 2);
8+
`
9+
const context = mockContext()
10+
const promise = runInContext(program, context, { scheduler: "preemptive" })
11+
return promise.then(obj => {
12+
expect(obj).toMatchSnapshot()
13+
expect(obj.status).toBe('finished')
14+
expect((obj as Finished).value).toBe(parseInt('1100101010101', 2))
15+
})
16+
})
17+
18+
test("parse_int with valid args is ok, radix 36", () => {
19+
const program = `
20+
parse_int('uu1', 36);
21+
`
22+
const context = mockContext()
23+
const promise = runInContext(program, context, { scheduler: "preemptive" })
24+
return promise.then(obj => {
25+
expect(obj).toMatchSnapshot()
26+
expect(obj.status).toBe('finished')
27+
expect((obj as Finished).value).toBe(parseInt('uu1', 36))
28+
})
29+
})
30+
31+
test("parse_int with valid args is ok, but invalid str for radix", () => {
32+
const program = `
33+
parse_int('uu1', 2);
34+
`
35+
const context = mockContext()
36+
const promise = runInContext(program, context, { scheduler: "preemptive" })
37+
return promise.then(obj => {
38+
expect(obj).toMatchSnapshot()
39+
expect(obj.status).toBe('finished')
40+
expect((obj as Finished).value).toBe(parseInt('uu1', 2))
41+
})
42+
})
43+
44+
test("parse_int with non-string arg str throws error", () => {
45+
const program = `
46+
parse_int(42, 2);
47+
`
48+
const context = mockContext()
49+
const promise = runInContext(program, context, { scheduler: "preemptive" })
50+
return promise.then(obj => {
51+
expect(obj).toMatchSnapshot()
52+
expect(obj.status).toBe('error')
53+
const errors = parseError(context.errors)
54+
expect(errors).toMatchSnapshot()
55+
})
56+
})
57+
58+
test("parse_int with non-integer arg radix throws error", () => {
59+
const program = `
60+
parse_int(42, 2.1);
61+
`
62+
const context = mockContext()
63+
const promise = runInContext(program, context, { scheduler: "preemptive" })
64+
return promise.then(obj => {
65+
expect(obj).toMatchSnapshot()
66+
expect(obj.status).toBe('error')
67+
const errors = parseError(context.errors)
68+
expect(errors).toMatchSnapshot()
69+
})
70+
})
71+
72+
test("parse_int with radix outside [2, 36] throws error, radix=1", () => {
73+
const program = `
74+
parse_int('10', 1);
75+
`
76+
const context = mockContext()
77+
const promise = runInContext(program, context, { scheduler: "preemptive" })
78+
return promise.then(obj => {
79+
expect(obj).toMatchSnapshot()
80+
expect(obj.status).toBe('error')
81+
const errors = parseError(context.errors)
82+
expect(errors).toMatchSnapshot()
83+
})
84+
})
85+
86+
test("parse_int with radix outside [2, 36] throws error, radix=37", () => {
87+
const program = `
88+
parse_int('10', 37);
89+
`
90+
const context = mockContext()
91+
const promise = runInContext(program, context, { scheduler: "preemptive" })
92+
return promise.then(obj => {
93+
expect(obj).toMatchSnapshot()
94+
expect(obj.status).toBe('error')
95+
const errors = parseError(context.errors)
96+
expect(errors).toMatchSnapshot()
97+
})
98+
})
99+
100+
test("parse_int with string arg radix throws error", () => {
101+
const program = `
102+
parse_int(42, '2');
103+
`
104+
const context = mockContext()
105+
const promise = runInContext(program, context, { scheduler: "preemptive" })
106+
return promise.then(obj => {
107+
expect(obj).toMatchSnapshot()
108+
expect(obj.status).toBe('error')
109+
const errors = parseError(context.errors)
110+
expect(errors).toMatchSnapshot()
111+
})
112+
})

src/stdlib/misc.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,20 @@ export function array_length(xs: Value[]) {
4343
}
4444
array_length.__SOURCE__ = 'array_length(xs)'
4545

46-
export function parse_int(inputString: string, radix: number) {
47-
const parsed = parseInt(inputString, radix)
48-
if (inputString && radix && parsed) {
49-
// the two arguments are provided, and parsed is not NaN
50-
return parsed
46+
/**
47+
* Source version of parseInt. Both arguments are required.
48+
*
49+
* @param str String representation of the integer to be parsed. Required.
50+
* @param radix Base to parse the given `str`. Required.
51+
*
52+
* An error is thrown if `str` is not of type string, or `radix` is not an
53+
* integer within the range 2, 36 inclusive.
54+
*/
55+
export function parse_int(str: string, radix: number) {
56+
if (typeof(str) === 'string' && typeof(radix) === 'number' && Number.isInteger(radix) && 2 <= radix && radix <= 36) {
57+
return parseInt(str, radix)
5158
} else {
52-
throw new Error('parse_int expects two arguments a string s, and a positive integer i')
59+
throw new Error('parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive.')
5360
}
5461
}
5562
parse_int.__SOURCE__ = 'parse_int(s, i)'

0 commit comments

Comments
 (0)