Skip to content

Commit 12598cd

Browse files
committed
CON-191: Extended testing to cover all use-cases
Also discovered that getJSON cannot be used for large ints (and in fact is worse than getNumber since we cannot detect when it would corrupt the value).
1 parent 61edcc5 commit 12598cd

1 file changed

Lines changed: 173 additions & 15 deletions

File tree

test/nodejs/test_rticonnextdds_data_access.js

Lines changed: 173 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,12 +1154,137 @@ describe('Tests with a testOutput and testInput', () => {
11541154
// the same restriction on 64-bit integers - their only Number type is a double
11551155
// precision floating point value, meaning they cannot accurately represent
11561156
// integers large than 2^53.
1157-
// These tests check that via the type-agnostic getter and setter, and getString
1158-
// and setString can be used to workaround this limitation.
1157+
// Due to this, there are restrictions on how 64-bit numbers (uint64 and int64)
1158+
// can be communicated, the following verify that the behaviour is as follows:
1159+
// - The getNumber and setNumber operations throw an error if used with a value
1160+
// outside of their supported range:
1161+
// - Max |value| for setNumber is 2^53 - 1
1162+
// - Max |value| for getNumber is 2^53
1163+
// - The type-agnostic setter can be used with numbers outside of this range,
1164+
// if they are supplied as strings (note in Python we also accept numbers).
1165+
// - The type-agnostic getter can be used with numbers outside of the range.
1166+
// If the value is <= 2^53 it will be returned as a Number, otherwise as a
1167+
// string.
1168+
// - The getString and setString operations can be used on all number types
1169+
// and has no restriction on size.
1170+
// - The setFromJson operation can be used to set large integers, they must
1171+
// be supplied as strings (otherwise they would be corrupted by JavaScript)
1172+
// - the getJSON operation should not be used to obtain large integers, the
1173+
// largest integer it can be used with is the same as getNumber (2^53), however
1174+
// we have no way of detecting if a value larger than this is being retrieved,
1175+
// so no error will be thrown otherwise.
11591176
describe('Tests with 64-bit integers', () => {
1177+
it('getNumber throws an error if value is out of range', async () => {
1178+
// Highest value retrievable is 2^53, so set 1 higher. We set via Json
1179+
// to work around the limitation with setNumber (could also use setString,
1180+
// or setAnyValue)
1181+
testOutput.instance.setFromJson({
1182+
my_uint64: '9007199254740993',
1183+
my_int64: '9007199254740993'
1184+
})
1185+
testOutput.write()
1186+
try {
1187+
await testInput.wait(testExpectSuccessTimeout)
1188+
} catch (err) {
1189+
console.log('Error caught: ' + err)
1190+
expect(false).to.deep.equals(true)
1191+
}
1192+
testInput.take()
1193+
1194+
// The values of the 64-bit integers is too large to retrieve with getNumber
1195+
expect(() => {
1196+
testInput.samples.get(0).getNumber('my_uint64')
1197+
}).to.throw(rti.DDSError)
1198+
expect(() => {
1199+
testInput.samples.get(0).getNumber('my_int64')
1200+
}).to.throw(rti.DDSError)
1201+
1202+
// Also check the most negative value
1203+
testOutput.instance.setFromJson({
1204+
my_int64: '-9007199254740993'
1205+
})
1206+
testOutput.write()
1207+
try {
1208+
await testInput.wait(testExpectSuccessTimeout)
1209+
} catch (err) {
1210+
console.log('Error caught: ' + err)
1211+
expect(false).to.deep.equals(true)
1212+
}
1213+
testInput.take()
1214+
expect(() => {
1215+
testInput.samples.get(0).getNumber('my_int64')
1216+
}).to.throw(rti.DDSError)
1217+
})
1218+
1219+
// Check that the getNumber API can handle values stated in documentation
1220+
it('getNumber can retrieve values up to 2^53', async () => {
1221+
testOutput.instance.setFromJson({
1222+
my_uint64: '9007199254740992',
1223+
my_int64: '-9007199254740992'
1224+
})
1225+
testOutput.write()
1226+
try {
1227+
await testInput.wait(testExpectSuccessTimeout)
1228+
} catch (err) {
1229+
console.log('Error caught: ' + err)
1230+
expect(false).to.deep.equals(true)
1231+
}
1232+
testInput.take()
1233+
1234+
// Obtain the values and confirm they are correct
1235+
const obtainedUint64 = testInput.samples.get(0).getNumber('my_uint64')
1236+
const obtainedInt64 = testInput.samples.get(0).getNumber('my_int64')
1237+
expect(obtainedUint64).to.deep.equals(Number.MAX_SAFE_INTEGER + 1)
1238+
expect(obtainedInt64).to.deep.equals(Number.MIN_SAFE_INTEGER - 1)
1239+
})
1240+
1241+
// Check that setNumber throws an error if value is too large
1242+
it('setNumber throws an error if value out of range', () => {
1243+
// Max value for set is 2^53 - 1, anything larger will throw an error
1244+
expect(() => {
1245+
testOutput.instance.setNumber('my_uint64', Number.MAX_SAFE_INTEGER + 1)
1246+
}).to.throw(rti.DDSError)
1247+
expect(() => {
1248+
testOutput.instance.setNumber('my_int64', Number.MAX_SAFE_INTEGER + 1)
1249+
}).to.throw(rti.DDSError)
1250+
expect(() => {
1251+
testOutput.instance.setNumber('my_int64', Number.MIN_SAFE_INTEGER - 1)
1252+
}).to.throw(rti.DDSError)
1253+
})
1254+
1255+
// Check that setNumber can handle the values stated in the documentation
1256+
it('setNumber can set values up to 2^53 - 1', async () => {
1257+
// setNumber can set up to 2^53 - 1 (which is === Number.MAX_SAFE_INTEGER)
1258+
testOutput.instance.setNumber('my_uint64', Number.MAX_SAFE_INTEGER)
1259+
testOutput.instance.setNumber('my_int64', Number.MAX_SAFE_INTEGER)
1260+
testOutput.write()
1261+
try {
1262+
await testInput.wait(testExpectSuccessTimeout)
1263+
} catch (err) {
1264+
console.log('Error caught: ' + err)
1265+
expect(false).to.deep.equals(true)
1266+
}
1267+
testInput.take()
1268+
// Confirm that the values are correct and not corrupted
1269+
expect(testInput.samples.get(0).getNumber('my_uint64')).to.deep.equals(Number.MAX_SAFE_INTEGER)
1270+
expect(testInput.samples.get(0).getNumber('my_int64')).to.deep.equals(Number.MAX_SAFE_INTEGER)
1271+
1272+
// Also do same test with minimum value
1273+
testOutput.instance.setNumber('my_int64', Number.MIN_SAFE_INTEGER)
1274+
testOutput.write()
1275+
try {
1276+
await testInput.wait(testExpectSuccessTimeout)
1277+
} catch (err) {
1278+
console.log('Error caught: ' + err)
1279+
expect(false).to.deep.equals(true)
1280+
}
1281+
testInput.take()
1282+
expect(testInput.samples.get(0).getNumber('my_int64')).to.deep.equals(Number.MIN_SAFE_INTEGER)
1283+
})
1284+
11601285
it('Can communicate large 64-bit numbers using getString and setString', async () => {
1161-
testOutput.instance.setString('my_uint64', '18446744073709551615')
1162-
testOutput.instance.setString('my_int64', '9223372036854775807')
1286+
testOutput.instance.setString('my_uint64', '9007199254740993')
1287+
testOutput.instance.setString('my_int64', '-9007199254740993')
11631288
testOutput.write()
11641289
try {
11651290
await testInput.wait(testExpectSuccessTimeout)
@@ -1168,14 +1293,16 @@ describe('Tests with a testOutput and testInput', () => {
11681293
expect(false).to.deep.equals(true)
11691294
}
11701295
testInput.take()
1171-
expect(testInput.samples.get(0).getString('my_uint64')).to.deep.equals('18446744073709551615')
1172-
expect(testInput.samples.get(0).getString('my_int64')).to.deep.equals('9223372036854775807')
1296+
expect(testInput.samples.get(0).getString('my_uint64')).to.deep.equals('9007199254740993')
1297+
expect(testInput.samples.get(0).getString('my_int64')).to.deep.equals('-9007199254740993')
11731298
})
11741299

11751300
it('64-bit values larger than 2^53 are returned as strings by get', async () => {
1176-
const maxInt64 = '9223372036854775807'
1177-
const maxUint64 = '18446744073709551615'
1178-
testOutput.instance.setFromJson({ my_int64: maxInt64, my_uint64: maxUint64 })
1301+
const largeIntAsString = '9007199254740993'
1302+
testOutput.instance.setFromJson({
1303+
my_int64: largeIntAsString,
1304+
my_uint64: largeIntAsString
1305+
})
11791306
testOutput.write()
11801307
try {
11811308
await testInput.wait(testExpectSuccessTimeout)
@@ -1185,13 +1312,16 @@ describe('Tests with a testOutput and testInput', () => {
11851312
}
11861313
testInput.take()
11871314
expect(testInput.samples.get(0).get('my_uint64')).to.be.a.string
1188-
expect(testInput.samples.get(0).get('my_uint64')).to.deep.equals(maxUint64)
1189-
expect(testInput.samples.get(0).get('my_int64')).to.deep.equals(maxInt64)
1315+
expect(testInput.samples.get(0).get('my_uint64')).to.deep.equals(largeIntAsString)
11901316
expect(testInput.samples.get(0).get('my_int64')).to.be.a.string
1317+
expect(testInput.samples.get(0).get('my_int64')).to.deep.equals(largeIntAsString)
11911318
})
11921319

11931320
it('64-bit values smaller or equal to 2^53 are returned as numbers by get', async () => {
1194-
testOutput.instance.setFromJson({ my_int64: 123456, my_uint64: 123456 })
1321+
testOutput.instance.setFromJson({
1322+
my_uint64: Number.MAX_SAFE_INTEGER,
1323+
my_int64: Number.MIN_SAFE_INTEGER
1324+
})
11951325
testOutput.write()
11961326
try {
11971327
await testInput.wait(testExpectSuccessTimeout)
@@ -1200,13 +1330,16 @@ describe('Tests with a testOutput and testInput', () => {
12001330
expect(false).to.deep.equals(true)
12011331
}
12021332
testInput.take()
1203-
expect(testInput.samples.get(0).get('my_uint64')).to.deep.equals(123456)
1333+
expect(testInput.samples.get(0).get('my_uint64')).to.deep.equals(Number.MAX_SAFE_INTEGER)
12041334
expect(testInput.samples.get(0).get('my_uint64')).to.be.a('number')
1205-
expect(testInput.samples.get(0).get('my_int64')).to.deep.equals(123456)
1335+
expect(testInput.samples.get(0).get('my_int64')).to.deep.equals(Number.MIN_SAFE_INTEGER)
12061336
expect(testInput.samples.get(0).get('my_int64')).to.be.a('number')
12071337
})
12081338

1209-
it('Can communicate large 64-bit numbers using type-agnostic getters and setters', async () => {
1339+
it('Can set large 64-bit numbers using type-agnostic setter', async () => {
1340+
// Any integer value can be set via the type-agnostic setter when supplied
1341+
// as a string (this differs from Python, where you could also supply it as
1342+
// an int))
12101343
testOutput.instance.set('my_uint64', '18446744073709551615')
12111344
testOutput.instance.set('my_int64', '9223372036854775807')
12121345
testOutput.write()
@@ -1217,9 +1350,34 @@ describe('Tests with a testOutput and testInput', () => {
12171350
expect(false).to.deep.equals(true)
12181351
}
12191352
testInput.take()
1353+
// The values will be returned as strings since they are > 2^53
12201354
expect(testInput.samples.get(0).get('my_uint64')).to.deep.equals('18446744073709551615')
12211355
expect(testInput.samples.get(0).get('my_int64')).to.deep.equals('9223372036854775807')
12221356
})
1357+
1358+
it('The JSON getter cannot handle large integers', async () => {
1359+
// Provided the values are supplied as strings to the JSON object, there should
1360+
// be no restriction on the size of the integer
1361+
const jsonTx = {
1362+
my_uint64: '18446744073709551615',
1363+
my_int64: '9223372036854775807'
1364+
}
1365+
testOutput.instance.setFromJson(jsonTx)
1366+
testOutput.write()
1367+
try {
1368+
await testInput.wait(testExpectSuccessTimeout)
1369+
} catch (err) {
1370+
console.log('Error caught: ' + err)
1371+
expect(false).to.deep.equals(true)
1372+
}
1373+
testInput.take()
1374+
1375+
// The JSON.parse() call done in getFromJSON will result in the
1376+
// values > Number.MAX_SAFE_INT being corrupted. We cannot detect this.
1377+
const jsonRx = testInput.samples.get(0).getJson()
1378+
expect(jsonRx.my_int64).to.not.deep.equal(jsonTx.my_int64)
1379+
expect(jsonRx.my_uint64).to.not.deep.equal(jsonTx.my_uint64)
1380+
})
12231381
})
12241382
})
12251383

0 commit comments

Comments
 (0)