From bac93b675269a7eca8c04c6c3578084903fc8de9 Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 14:25:35 -0400 Subject: [PATCH 01/10] feat(NODE-6087): add Int32.fromString method --- src/int_32.ts | 10 ++++++++++ test/node/int_32_tests.js | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/int_32.ts b/src/int_32.ts index 31b13c15a..3ab699ccb 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -1,4 +1,5 @@ import { BSONValue } from './bson_value'; +import { BSONError } from './error'; import type { EJSONOptions } from './extended_json'; import { type InspectFn, defaultInspect } from './parser/utils'; @@ -32,6 +33,15 @@ export class Int32 extends BSONValue { this.value = +value | 0; } + static fromString(value: string): number { + const trimmedValue = value.trim(); + const coercedValue = Number(trimmedValue); + if (coercedValue.toString() !== trimmedValue) { + throw new BSONError(`Input: '${value}' is not a valid Int32 string`); + } + return coercedValue; + } + /** * Access the number value. * diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index 27d7adfcc..7a6c73331 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -97,4 +97,45 @@ describe('Int32', function () { }); } }); + + describe('fromString', () => { + const acceptedInputs = [ + ['Int32.max', '2147483647', 2147483647], + ['Int32.min', '-2147483648', -2147483648], + ['zero', '0', 0], + ['leading and trailing whitespace', ' 89 ', 89] + ]; + const errorInputs = [ + ['Int32.max + 1', '2147483648'], + ['Int32.min - 1', '-2147483649'], + ['positive integer with decimal', '2.0'], + ['zero with decimal', '0.0'], + ['negative zero', '-0'], + ['Infinity', 'Infinity'], + ['-Infinity', '-Infinity'], + ['NaN', 'NaN'], + ['fraction', '2/3'], + ['leading zeros', '-00007'], + ['commas', '34,450'] + ]; + + for (const [testName, value, expectedInt32] of acceptedInputs) { + context(`when case is ${testName}`, () => { + it(`should return Int32 that matches expected value`, () => { + expect(Int32.fromString(value)).to.equal(expectedInt32); + }); + }); + } + for (const [testName, value] of errorInputs) { + context(`when case is ${testName}`, () => { + it(`should throw error`, () => { + try { + Int32.fromString(value); + } catch (error) { + expect(error.message).to.equal(`Input: '${value}' is not a valid Int32 string`); + } + }); + }); + } + }); }); From 82a52604f6c4bd97f0afe7faee3a992782516e3c Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 14:40:47 -0400 Subject: [PATCH 02/10] added API docs and additional test cases" --- src/int_32.ts | 13 +++++++++++++ test/node/int_32_tests.js | 6 +++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/int_32.ts b/src/int_32.ts index 3ab699ccb..b8e714441 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -33,6 +33,19 @@ export class Int32 extends BSONValue { this.value = +value | 0; } + /** + * Attempt to create an Int32 type from string. + * + * This method will throw a BSONError on any string input that is not representable as an Int32. + * Notably, this method will also throw on the following string formats: + * - Strings in non-decimal formats (exponent notation, binary, hex, or octal digits) + * - Strings with leading zeros + * - Strings with decimal points (ex: '2.0') + * + * Strings with whitespace, however, are allowed. + * + * @param value - the string we want to represent as an int32. + */ static fromString(value: string): number { const trimmedValue = value.trim(); const coercedValue = Number(trimmedValue); diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index 7a6c73331..b1e728d97 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -116,7 +116,11 @@ describe('Int32', function () { ['NaN', 'NaN'], ['fraction', '2/3'], ['leading zeros', '-00007'], - ['commas', '34,450'] + ['commas', '34,450'], + ['exponentiation notation', '1e1'], + ['octal', '0o1'], + ['binary', '0b1'], + ['hex', '0x1'] ]; for (const [testName, value, expectedInt32] of acceptedInputs) { From 3cf855b3ef7df30d3161a84f10e5ed6e01aec747 Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 15:23:36 -0400 Subject: [PATCH 03/10] add support for leading zeros, and test case for empty string --- src/int_32.ts | 14 +++++++++----- test/node/int_32_tests.js | 10 +++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/int_32.ts b/src/int_32.ts index b8e714441..455ff3790 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -39,17 +39,21 @@ export class Int32 extends BSONValue { * This method will throw a BSONError on any string input that is not representable as an Int32. * Notably, this method will also throw on the following string formats: * - Strings in non-decimal formats (exponent notation, binary, hex, or octal digits) - * - Strings with leading zeros - * - Strings with decimal points (ex: '2.0') + * - Strings with non-numeric characters (ex: '2.0', '24,000') * - * Strings with whitespace, however, are allowed. + * Strings with whitespace and/or leading zeros, however, are allowed. * * @param value - the string we want to represent as an int32. */ static fromString(value: string): number { const trimmedValue = value.trim(); - const coercedValue = Number(trimmedValue); - if (coercedValue.toString() !== trimmedValue) { + const cleanedValue = !/[^0]+/.test(trimmedValue) + ? trimmedValue.replace(/^0+/, '0') // all zeros case + : trimmedValue.includes('-') + ? trimmedValue.replace(/^-0+/, '-') // negative number with leading zeros + : trimmedValue.replace(/^0+/, ''); // positive number with leading zeros + const coercedValue = Number(cleanedValue); + if (coercedValue.toString() !== cleanedValue) { throw new BSONError(`Input: '${value}' is not a valid Int32 string`); } return coercedValue; diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index b1e728d97..dc1fb7746 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -103,7 +103,11 @@ describe('Int32', function () { ['Int32.max', '2147483647', 2147483647], ['Int32.min', '-2147483648', -2147483648], ['zero', '0', 0], - ['leading and trailing whitespace', ' 89 ', 89] + ['zero with leading zeros', '000000', 0], + ['non-leading zeros', '45000000', 45000000], + ['leading and trailing whitespace', ' 89 ', 89], + ['positive leading zeros', '000000867', 867], + ['negative leading zeros', '-00007', -7] ]; const errorInputs = [ ['Int32.max + 1', '2147483648'], @@ -115,12 +119,12 @@ describe('Int32', function () { ['-Infinity', '-Infinity'], ['NaN', 'NaN'], ['fraction', '2/3'], - ['leading zeros', '-00007'], ['commas', '34,450'], ['exponentiation notation', '1e1'], ['octal', '0o1'], ['binary', '0b1'], - ['hex', '0x1'] + ['hex', '0x1'], + ['empty string', ''] ]; for (const [testName, value, expectedInt32] of acceptedInputs) { From 8f05f13d3d162fdfe3bb8e32b7743de6e7750516 Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 16:24:42 -0400 Subject: [PATCH 04/10] fixed test error assertion, and refined cases to error on" --- src/int_32.ts | 25 ++++++++++++++++--------- test/node/int_32_tests.js | 15 ++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/int_32.ts b/src/int_32.ts index 455ff3790..1dbfa49e0 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -1,4 +1,5 @@ import { BSONValue } from './bson_value'; +import { BSON_INT32_MAX, BSON_INT32_MIN } from './constants'; import { BSONError } from './error'; import type { EJSONOptions } from './extended_json'; import { type InspectFn, defaultInspect } from './parser/utils'; @@ -40,20 +41,26 @@ export class Int32 extends BSONValue { * Notably, this method will also throw on the following string formats: * - Strings in non-decimal formats (exponent notation, binary, hex, or octal digits) * - Strings with non-numeric characters (ex: '2.0', '24,000') + * - Strings with leading and/or trailing whitespace * - * Strings with whitespace and/or leading zeros, however, are allowed. + * Strings with leading zeros, however, are also allowed * * @param value - the string we want to represent as an int32. */ static fromString(value: string): number { - const trimmedValue = value.trim(); - const cleanedValue = !/[^0]+/.test(trimmedValue) - ? trimmedValue.replace(/^0+/, '0') // all zeros case - : trimmedValue.includes('-') - ? trimmedValue.replace(/^-0+/, '-') // negative number with leading zeros - : trimmedValue.replace(/^0+/, ''); // positive number with leading zeros - const coercedValue = Number(cleanedValue); - if (coercedValue.toString() !== cleanedValue) { + const cleanedValue = !/[^0]+/.test(value) + ? value.replace(/^0+/, '0') // all zeros case + : value.includes('-') + ? value.replace(/^-0+/, '-') // negative number with leading zeros + : value.replace(/^0+/, ''); // positive number with leading zeros + + const coercedValue = Number(value); + if ( + coercedValue.toString() !== cleanedValue || + !Number.isSafeInteger(coercedValue) || + BSON_INT32_MAX < coercedValue || + BSON_INT32_MIN > coercedValue + ) { throw new BSONError(`Input: '${value}' is not a valid Int32 string`); } return coercedValue; diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index dc1fb7746..681aed1bb 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -2,6 +2,7 @@ const BSON = require('../register-bson'); const Int32 = BSON.Int32; +const BSONError = BSON.BSONError; describe('Int32', function () { context('Constructor', function () { @@ -103,9 +104,8 @@ describe('Int32', function () { ['Int32.max', '2147483647', 2147483647], ['Int32.min', '-2147483648', -2147483648], ['zero', '0', 0], - ['zero with leading zeros', '000000', 0], ['non-leading zeros', '45000000', 45000000], - ['leading and trailing whitespace', ' 89 ', 89], + ['zero with leading zeros', '000000', 0], ['positive leading zeros', '000000867', 867], ['negative leading zeros', '-00007', -7] ]; @@ -124,7 +124,8 @@ describe('Int32', function () { ['octal', '0o1'], ['binary', '0b1'], ['hex', '0x1'], - ['empty string', ''] + ['empty string', ''], + ['leading and trailing whitespace', ' 89 ', 89] ]; for (const [testName, value, expectedInt32] of acceptedInputs) { @@ -136,12 +137,8 @@ describe('Int32', function () { } for (const [testName, value] of errorInputs) { context(`when case is ${testName}`, () => { - it(`should throw error`, () => { - try { - Int32.fromString(value); - } catch (error) { - expect(error.message).to.equal(`Input: '${value}' is not a valid Int32 string`); - } + it(`should throw correct error`, () => { + expect(() => Int32.fromString(value)).to.throw(BSONError, /not a valid Int32 string/); }); }); } From e672708f8884799a7ee6d1a9eb5b820321e2945e Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 17:34:11 -0400 Subject: [PATCH 05/10] changed to return an Int32 --- src/int_32.ts | 6 +++--- test/node/int_32_tests.js | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/int_32.ts b/src/int_32.ts index 1dbfa49e0..bc3adce5f 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -47,10 +47,10 @@ export class Int32 extends BSONValue { * * @param value - the string we want to represent as an int32. */ - static fromString(value: string): number { + static fromString(value: string): Int32 { const cleanedValue = !/[^0]+/.test(value) ? value.replace(/^0+/, '0') // all zeros case - : value.includes('-') + : value[0] === '-' ? value.replace(/^-0+/, '-') // negative number with leading zeros : value.replace(/^0+/, ''); // positive number with leading zeros @@ -63,7 +63,7 @@ export class Int32 extends BSONValue { ) { throw new BSONError(`Input: '${value}' is not a valid Int32 string`); } - return coercedValue; + return new Int32(coercedValue); } /** diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index 681aed1bb..febfd5734 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -101,13 +101,13 @@ describe('Int32', function () { describe('fromString', () => { const acceptedInputs = [ - ['Int32.max', '2147483647', 2147483647], - ['Int32.min', '-2147483648', -2147483648], - ['zero', '0', 0], - ['non-leading zeros', '45000000', 45000000], - ['zero with leading zeros', '000000', 0], - ['positive leading zeros', '000000867', 867], - ['negative leading zeros', '-00007', -7] + ['Int32.max', '2147483647', new Int32(2147483647)], + ['Int32.min', '-2147483648', new Int32(-2147483648)], + ['zero', '0', new Int32(0)], + ['non-leading zeros', '45000000', new Int32(45000000)], + ['zero with leading zeros', '000000', new Int32(0)], + ['positive leading zeros', '000000867', new Int32(867)], + ['negative leading zeros', '-00007', new Int32(-7)] ]; const errorInputs = [ ['Int32.max + 1', '2147483648'], @@ -131,7 +131,7 @@ describe('Int32', function () { for (const [testName, value, expectedInt32] of acceptedInputs) { context(`when case is ${testName}`, () => { it(`should return Int32 that matches expected value`, () => { - expect(Int32.fromString(value)).to.equal(expectedInt32); + expect(Int32.fromString(value).value).to.equal(expectedInt32.value); }); }); } From ab66c65395e0bf42746baab07189392ee8aa263a Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 17:38:20 -0400 Subject: [PATCH 06/10] handle explicit positive case --- src/int_32.ts | 4 ++-- test/node/int_32_tests.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/int_32.ts b/src/int_32.ts index bc3adce5f..48b458918 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -40,7 +40,7 @@ export class Int32 extends BSONValue { * This method will throw a BSONError on any string input that is not representable as an Int32. * Notably, this method will also throw on the following string formats: * - Strings in non-decimal formats (exponent notation, binary, hex, or octal digits) - * - Strings with non-numeric characters (ex: '2.0', '24,000') + * - Strings with non-numeric or sign characters (ex: '2.0', '24,000') * - Strings with leading and/or trailing whitespace * * Strings with leading zeros, however, are also allowed @@ -52,7 +52,7 @@ export class Int32 extends BSONValue { ? value.replace(/^0+/, '0') // all zeros case : value[0] === '-' ? value.replace(/^-0+/, '-') // negative number with leading zeros - : value.replace(/^0+/, ''); // positive number with leading zeros + : value.replace(/^\+?0+/, ''); // positive number with leading zeros const coercedValue = Number(value); if ( diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index febfd5734..872216f5c 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -107,6 +107,7 @@ describe('Int32', function () { ['non-leading zeros', '45000000', new Int32(45000000)], ['zero with leading zeros', '000000', new Int32(0)], ['positive leading zeros', '000000867', new Int32(867)], + ['explicity positive leading zeros', '+000000867', new Int32(867)], ['negative leading zeros', '-00007', new Int32(-7)] ]; const errorInputs = [ From 553df255b2d48189105c1986e9c6e476797ee78e Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 17:48:42 -0400 Subject: [PATCH 07/10] fixed wording of docs comment --- src/int_32.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/int_32.ts b/src/int_32.ts index 48b458918..61bb2f855 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -40,7 +40,7 @@ export class Int32 extends BSONValue { * This method will throw a BSONError on any string input that is not representable as an Int32. * Notably, this method will also throw on the following string formats: * - Strings in non-decimal formats (exponent notation, binary, hex, or octal digits) - * - Strings with non-numeric or sign characters (ex: '2.0', '24,000') + * - Strings with characters other than sign or numeric characters (ex: '2.0', '24,000') * - Strings with leading and/or trailing whitespace * * Strings with leading zeros, however, are also allowed From 8252fcd36e62de1406f41e34268f7388ccd7fa84 Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Tue, 16 Apr 2024 17:49:28 -0400 Subject: [PATCH 08/10] fixed wording of docs comment 2 --- src/int_32.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/int_32.ts b/src/int_32.ts index 61bb2f855..c49bf529b 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -40,7 +40,7 @@ export class Int32 extends BSONValue { * This method will throw a BSONError on any string input that is not representable as an Int32. * Notably, this method will also throw on the following string formats: * - Strings in non-decimal formats (exponent notation, binary, hex, or octal digits) - * - Strings with characters other than sign or numeric characters (ex: '2.0', '24,000') + * - Strings non-numeric and non-leading sign characters (ex: '2.0', '24,000') * - Strings with leading and/or trailing whitespace * * Strings with leading zeros, however, are also allowed From 9356cf0495554488a787fa810af0e2b72fced7b1 Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Wed, 17 Apr 2024 11:08:44 -0400 Subject: [PATCH 09/10] remove wrappers in expected value + fix docs grammar --- src/int_32.ts | 2 +- test/node/int_32_tests.js | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/int_32.ts b/src/int_32.ts index c49bf529b..59279ee98 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -43,7 +43,7 @@ export class Int32 extends BSONValue { * - Strings non-numeric and non-leading sign characters (ex: '2.0', '24,000') * - Strings with leading and/or trailing whitespace * - * Strings with leading zeros, however, are also allowed + * Strings with leading zeros, however, are allowed. * * @param value - the string we want to represent as an int32. */ diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index 872216f5c..54614ba96 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -101,14 +101,14 @@ describe('Int32', function () { describe('fromString', () => { const acceptedInputs = [ - ['Int32.max', '2147483647', new Int32(2147483647)], - ['Int32.min', '-2147483648', new Int32(-2147483648)], - ['zero', '0', new Int32(0)], - ['non-leading zeros', '45000000', new Int32(45000000)], - ['zero with leading zeros', '000000', new Int32(0)], - ['positive leading zeros', '000000867', new Int32(867)], - ['explicity positive leading zeros', '+000000867', new Int32(867)], - ['negative leading zeros', '-00007', new Int32(-7)] + ['Int32.max', '2147483647', 2147483647], + ['Int32.min', '-2147483648', -2147483648], + ['zero', '0', 0], + ['non-leading zeros', '45000000', 45000000], + ['zero with leading zeros', '000000', 0], + ['positive leading zeros', '000000867', 867], + ['explicity positive leading zeros', '+000000867', 867], + ['negative leading zeros', '-00007', -7] ]; const errorInputs = [ ['Int32.max + 1', '2147483648'], @@ -132,7 +132,7 @@ describe('Int32', function () { for (const [testName, value, expectedInt32] of acceptedInputs) { context(`when case is ${testName}`, () => { it(`should return Int32 that matches expected value`, () => { - expect(Int32.fromString(value).value).to.equal(expectedInt32.value); + expect(Int32.fromString(value).value).to.equal(expectedInt32); }); }); } From 0c1fcf71e927fca7b4bbe8509dd350ce4af6e96c Mon Sep 17 00:00:00 2001 From: Aditi Khare Date: Wed, 17 Apr 2024 14:09:13 -0400 Subject: [PATCH 10/10] requested changes and clean up --- src/int_32.ts | 15 ++++++----- test/node/int_32_tests.js | 54 +++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/int_32.ts b/src/int_32.ts index 59279ee98..f394f7af6 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -55,12 +55,15 @@ export class Int32 extends BSONValue { : value.replace(/^\+?0+/, ''); // positive number with leading zeros const coercedValue = Number(value); - if ( - coercedValue.toString() !== cleanedValue || - !Number.isSafeInteger(coercedValue) || - BSON_INT32_MAX < coercedValue || - BSON_INT32_MIN > coercedValue - ) { + + if (BSON_INT32_MAX < coercedValue) { + throw new BSONError(`Input: '${value}' is larger than the maximum value for Int32`); + } else if (BSON_INT32_MIN > coercedValue) { + throw new BSONError(`Input: '${value}' is smaller than the minimum value for Int32`); + } else if (!Number.isSafeInteger(coercedValue)) { + throw new BSONError(`Input: '${value}' is not a safe integer`); + } else if (coercedValue.toString() !== cleanedValue) { + // catch all case throw new BSONError(`Input: '${value}' is not a valid Int32 string`); } return new Int32(coercedValue); diff --git a/test/node/int_32_tests.js b/test/node/int_32_tests.js index 54614ba96..44f2b7440 100644 --- a/test/node/int_32_tests.js +++ b/test/node/int_32_tests.js @@ -104,42 +104,42 @@ describe('Int32', function () { ['Int32.max', '2147483647', 2147483647], ['Int32.min', '-2147483648', -2147483648], ['zero', '0', 0], - ['non-leading zeros', '45000000', 45000000], - ['zero with leading zeros', '000000', 0], - ['positive leading zeros', '000000867', 867], - ['explicity positive leading zeros', '+000000867', 867], - ['negative leading zeros', '-00007', -7] + ['a string with non-leading consecutive zeros', '45000000', 45000000], + ['a string with zero with leading zeros', '000000', 0], + ['a string with positive leading zeros', '000000867', 867], + ['a string with explicity positive leading zeros', '+000000867', 867], + ['a string with negative leading zeros', '-00007', -7] ]; const errorInputs = [ - ['Int32.max + 1', '2147483648'], - ['Int32.min - 1', '-2147483649'], - ['positive integer with decimal', '2.0'], - ['zero with decimal', '0.0'], - ['negative zero', '-0'], - ['Infinity', 'Infinity'], - ['-Infinity', '-Infinity'], - ['NaN', 'NaN'], - ['fraction', '2/3'], - ['commas', '34,450'], - ['exponentiation notation', '1e1'], - ['octal', '0o1'], - ['binary', '0b1'], - ['hex', '0x1'], - ['empty string', ''], - ['leading and trailing whitespace', ' 89 ', 89] + ['Int32.max + 1', '2147483648', 'larger than the maximum value for Int32'], + ['Int32.min - 1', '-2147483649', 'smaller than the minimum value for Int32'], + ['positive integer with decimal', '2.0', 'not a valid Int32 string'], + ['zero with decimals', '0.0', 'not a valid Int32 string'], + ['negative zero', '-0', 'not a valid Int32 string'], + ['Infinity', 'Infinity', 'larger than the maximum value for Int32'], + ['-Infinity', '-Infinity', 'smaller than the minimum value for Int32'], + ['NaN', 'NaN', 'not a safe integer'], + ['a fraction', '2/3', 'not a safe integer'], + ['a string containing commas', '34,450', 'not a safe integer'], + ['a string in exponentiation notation', '1e1', 'not a valid Int32 string'], + ['a octal string', '0o1', 'not a valid Int32 string'], + ['a binary string', '0b1', 'not a valid Int32 string'], + ['a hexadecimal string', '0x1', 'not a valid Int32 string'], + ['a empty string', '', 'not a valid Int32 string'], + ['a leading and trailing whitespace', ' 89 ', 'not a valid Int32 string'] ]; for (const [testName, value, expectedInt32] of acceptedInputs) { - context(`when case is ${testName}`, () => { - it(`should return Int32 that matches expected value`, () => { + context(`when the input is ${testName}`, () => { + it(`should successfully return an Int32 representation`, () => { expect(Int32.fromString(value).value).to.equal(expectedInt32); }); }); } - for (const [testName, value] of errorInputs) { - context(`when case is ${testName}`, () => { - it(`should throw correct error`, () => { - expect(() => Int32.fromString(value)).to.throw(BSONError, /not a valid Int32 string/); + for (const [testName, value, expectedErrMsg] of errorInputs) { + context(`when the input is ${testName}`, () => { + it(`should throw an error containing '${expectedErrMsg}'`, () => { + expect(() => Int32.fromString(value)).to.throw(BSONError, expectedErrMsg); }); }); }