Skip to content

Commit 3ae3df1

Browse files
authored
Add property-based testing to DateTime serialisation (#999)
1 parent af9cd46 commit 3ae3df1

File tree

7 files changed

+796
-22
lines changed

7 files changed

+796
-22
lines changed

packages/bolt-connection/package-lock.json

+42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bolt-connection/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"homepage": "https://github.com/neo4j/neo4j-javascript-driver#readme",
3333
"devDependencies": {
3434
"@types/jest": "^27.1.4",
35+
"fast-check": "^3.1.3",
3536
"jest": "^27.1.4",
3637
"lolex": "^6.0.0",
3738
"ts-jest": "^27.1.4",

packages/bolt-connection/test/bolt/bolt-protocol-v4x3.test.js

+86-7
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ import {
3939

4040
import { alloc } from '../../src/channel'
4141
import { structure } from '../../src/packstream'
42+
import fc from 'fast-check'
4243

4344
const WRITE = 'WRITE'
4445

4546
const {
4647
txConfig: { TxConfig },
4748
bookmarks: { Bookmarks },
48-
logger: { Logger }
49+
logger: { Logger },
50+
temporalUtil
4951
} = internal
5052

5153
describe('#unit BoltProtocolV4x3', () => {
@@ -822,6 +824,11 @@ describe('#unit BoltProtocolV4x3', () => {
822824
const packable = protocol.packable(object)
823825

824826
expect(packable).not.toThrow()
827+
expect(loggerFunction)
828+
.toBeCalledWith('warn',
829+
'DateTime objects without "timeZoneOffsetSeconds" property ' +
830+
'are prune to bugs related to ambiguous times. For instance, ' +
831+
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
825832

826833
buffer.reset()
827834

@@ -841,15 +848,87 @@ describe('#unit BoltProtocolV4x3', () => {
841848
unpacked.timeZoneId
842849
)
843850

844-
expect(loggerFunction)
845-
.toBeCalledWith('warn',
846-
'DateTime objects without "timeZoneOffsetSeconds" property ' +
847-
'are prune to bugs related to ambiguous times. For instance, ' +
848-
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
849-
850851
expect(unpackedDateTimeWithoutOffset).toEqual(object)
851852
})
852853

854+
it('should pack and unpack DateTimeWithOffset', () => {
855+
fc.assert(
856+
fc.property(
857+
fc.date({
858+
min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
859+
max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
860+
}),
861+
fc.integer({ min: 0, max: 999_999 }),
862+
utils.arbitraryTimeZoneId(),
863+
(date, nanoseconds, timeZoneId) => {
864+
const object = new DateTime(
865+
date.getUTCFullYear(),
866+
date.getUTCMonth() + 1,
867+
date.getUTCDate(),
868+
date.getUTCHours(),
869+
date.getUTCMinutes(),
870+
date.getUTCSeconds(),
871+
date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
872+
undefined,
873+
timeZoneId
874+
)
875+
876+
buffer.reset()
877+
878+
const packable = protocol.packable(object)
879+
880+
expect(packable).not.toThrow()
881+
expect(loggerFunction)
882+
.toBeCalledWith('warn',
883+
'DateTime objects without "timeZoneOffsetSeconds" property ' +
884+
'are prune to bugs related to ambiguous times. For instance, ' +
885+
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
886+
887+
buffer.reset()
888+
889+
const unpacked = protocol.unpack(buffer)
890+
891+
expect(unpacked.timeZoneOffsetSeconds).toBeDefined()
892+
893+
const unpackedDateTimeWithoutOffset = new DateTime(
894+
unpacked.year,
895+
unpacked.month,
896+
unpacked.day,
897+
unpacked.hour,
898+
unpacked.minute,
899+
unpacked.second,
900+
unpacked.nanosecond,
901+
undefined,
902+
unpacked.timeZoneId
903+
)
904+
905+
expect(unpackedDateTimeWithoutOffset).toEqual(object)
906+
})
907+
)
908+
})
909+
910+
it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
911+
fc.assert(
912+
fc.property(fc.date(), date => {
913+
const object = DateTime.fromStandardDate(date)
914+
915+
buffer.reset()
916+
917+
const packable = protocol.packable(object)
918+
919+
expect(packable).not.toThrow()
920+
921+
buffer.reset()
922+
923+
const unpacked = protocol.unpack(buffer)
924+
925+
expect(unpacked.timeZoneOffsetSeconds).toBeDefined()
926+
927+
expect(unpacked).toEqual(object)
928+
})
929+
)
930+
})
931+
853932
it.each([
854933
[
855934
'DateTimeWithZoneOffset with less fields',

packages/bolt-connection/test/bolt/bolt-protocol-v4x4.test.js

+86-7
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ import {
3939

4040
import { alloc } from '../../src/channel'
4141
import { structure } from '../../src/packstream'
42+
import fc from 'fast-check'
4243

4344
const WRITE = 'WRITE'
4445

4546
const {
4647
txConfig: { TxConfig },
4748
bookmarks: { Bookmarks },
48-
logger: { Logger }
49+
logger: { Logger },
50+
temporalUtil
4951
} = internal
5052

5153
describe('#unit BoltProtocolV4x4', () => {
@@ -855,6 +857,11 @@ describe('#unit BoltProtocolV4x4', () => {
855857
const packable = protocol.packable(object)
856858

857859
expect(packable).not.toThrow()
860+
expect(loggerFunction)
861+
.toBeCalledWith('warn',
862+
'DateTime objects without "timeZoneOffsetSeconds" property ' +
863+
'are prune to bugs related to ambiguous times. For instance, ' +
864+
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
858865

859866
buffer.reset()
860867

@@ -874,15 +881,87 @@ describe('#unit BoltProtocolV4x4', () => {
874881
unpacked.timeZoneId
875882
)
876883

877-
expect(loggerFunction)
878-
.toBeCalledWith('warn',
879-
'DateTime objects without "timeZoneOffsetSeconds" property ' +
880-
'are prune to bugs related to ambiguous times. For instance, ' +
881-
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
882-
883884
expect(unpackedDateTimeWithoutOffset).toEqual(object)
884885
})
885886

887+
it('should pack and unpack DateTimeWithOffset', () => {
888+
fc.assert(
889+
fc.property(
890+
fc.date({
891+
min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
892+
max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
893+
}),
894+
fc.integer({ min: 0, max: 999_999 }),
895+
utils.arbitraryTimeZoneId(),
896+
(date, nanoseconds, timeZoneId) => {
897+
const object = new DateTime(
898+
date.getUTCFullYear(),
899+
date.getUTCMonth() + 1,
900+
date.getUTCDate(),
901+
date.getUTCHours(),
902+
date.getUTCMinutes(),
903+
date.getUTCSeconds(),
904+
date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
905+
undefined,
906+
timeZoneId
907+
)
908+
909+
buffer.reset()
910+
911+
const packable = protocol.packable(object)
912+
913+
expect(packable).not.toThrow()
914+
expect(loggerFunction)
915+
.toBeCalledWith('warn',
916+
'DateTime objects without "timeZoneOffsetSeconds" property ' +
917+
'are prune to bugs related to ambiguous times. For instance, ' +
918+
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
919+
920+
buffer.reset()
921+
922+
const unpacked = protocol.unpack(buffer)
923+
924+
expect(unpacked.timeZoneOffsetSeconds).toBeDefined()
925+
926+
const unpackedDateTimeWithoutOffset = new DateTime(
927+
unpacked.year,
928+
unpacked.month,
929+
unpacked.day,
930+
unpacked.hour,
931+
unpacked.minute,
932+
unpacked.second,
933+
unpacked.nanosecond,
934+
undefined,
935+
unpacked.timeZoneId
936+
)
937+
938+
expect(unpackedDateTimeWithoutOffset).toEqual(object)
939+
})
940+
)
941+
})
942+
943+
it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
944+
fc.assert(
945+
fc.property(fc.date(), date => {
946+
const object = DateTime.fromStandardDate(date)
947+
948+
buffer.reset()
949+
950+
const packable = protocol.packable(object)
951+
952+
expect(packable).not.toThrow()
953+
954+
buffer.reset()
955+
956+
const unpacked = protocol.unpack(buffer)
957+
958+
expect(unpacked.timeZoneOffsetSeconds).toBeDefined()
959+
960+
expect(unpacked).toEqual(object)
961+
})
962+
)
963+
})
964+
886965
it.each([
887966
[
888967
'DateTimeWithZoneOffset with less fields',

0 commit comments

Comments
 (0)