test("fuzz sessionCheck w/ value", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (value) => {
			try {
				await sessionCheck(sub, value);
			} catch (e) {
				catchError(value, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `sessionCheck` should handle various input values without causing errors, where expected errors are "400 Bad Request", "401 Unauthorized", "404 Not Found", or "409 Conflict".


unknown

test("fuzz sessionExpire w/ id", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (id) => {
			try {
				await sessionExpire(sub, id);
			} catch (e) {
				catchError(id, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `sessionExpire` should handle various inputs for `id` without throwing unexpected errors.


test("fuzz sessionRemove w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await sessionRemove(sub, testSession.id);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: Verifies that `sessionRemove` handles all types of inputs for `sub` without producing unexpected errors.


it('should maintain backward compatibility', () => {
      fc.assert(
        fc.property(
          fc.constantFrom('v1', 'v2', 'v3'),
          domainArbitraries.fullLessonPlan,
          (apiVersion, lessonPlan) => {
            // Property: API versions should maintain backward compatibility
            const transformForVersion = (data: typeof lessonPlan, version: string) => {
              switch (version) {
                case 'v1':
                  // v1 had simpler structure
                  return {
                    id: data.id,
                    title: data.title,
                    date: data.date,
                    duration: data.duration,
                    content: data.action, // Combined content
                  };

                case 'v2':
                  // v2 introduced three-part structure
                  return {
                    id: data.id,
                    title: data.title,
                    date: data.date,
                    duration: data.duration,
                    mindsOn: data.mindsOn,
                    action: data.action,
                    consolidation: data.consolidation,
                  };

                case 'v3':
                  // v3 is current full structure
                  return data;

                default:
                  return data;
              }
            };

            const versionData = transformForVersion(lessonPlan, apiVersion);

            // All versions should have core required fields
            return versionData.id && versionData.title && versionData.date && versionData.duration;
          },
        ),
        getPropertyTestConfig('fast'),
      );
    })

Summary: API versions 'v1', 'v2', and 'v3' should maintain core required fields (`id`, `title`, `date`, `duration`) for backward compatibility.


test("fuzz emailAddressExists w/ `username`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (username) => {
			try {
				await emailAddressExists(username);
			} catch (e) {
				catchError(username, e);
			}
		}),
		{
			numRuns: 10,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The test checks that the `emailAddressExists` function, when provided any input as `username`, only throws errors that match expected HTTP error messages.


test("fuzz emailAddressSelect w/ `sub`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await emailAddressSelect(sub, testMessenger.id);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 10,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `emailAddressSelect` with various inputs should not produce uncaught errors outside of specific expected error messages.


test("fuzz emailAddressCreate w/ `values`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (values) => {
			try {
				await emailAddressCreate(sub, testMessenger.value, { name: values });
			} catch (e) {
				catchError(values, e);
			}
		}),
		{
			numRuns: 10,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The `emailAddressCreate` function should handle a variety of `values` inputs without causing unexpected errors.


test("fuzz emailAddressRemove w/ `sub`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await emailAddressRemove(sub, testMessenger.id);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 10,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The `emailAddressRemove` function should handle inputs without throwing unexpected errors, capturing only specific expected error messages.


test("fuzz emailAddressRemove w/ `id`", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (id) => {
			try {
				await emailAddressRemove(sub, id);
			} catch (e) {
				catchError(id, e);
			}
		}),
		{
			numRuns: 10,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `emailAddressRemove` should handle various inputs for `id` without causing unexpected errors, specifically emitting only recognized errors.


test("fuzz accountExists w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accountExists(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accountExists` should handle various inputs without throwing unexpected errors, allowing only specified errors ("400 Bad Request", "401 Unauthorized", "404 Not Found", "409 Conflict").


test("fuzz accountCreate w/ values", async () => {
	await fc.assert(
		fc.asyncProperty(fc.string(), async (values) => {
			try {
				await accountCreate({ name: values });
			} catch (e) {
				catchError(values, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The `accountCreate` function should handle inputs without triggering errors other than "400 Bad Request," "401 Unauthorized," "404 Not Found," or "409 Conflict."


test("fuzz accountUpdate w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accountUpdate(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accountUpdate` should handle various inputs without throwing unexpected errors, where expected errors are defined as "400 Bad Request", "401 Unauthorized", "404 Not Found", and "409 Conflict".


test("fuzz accountExpire w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accountExpire(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The `accountExpire` function should not throw unexpected errors for arbitrary subscription inputs, with only specific errors being permissible.


test("fuzz accessTokenExists w/ username", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (username) => {
			try {
				await accessTokenExists(username);
			} catch (e) {
				catchError(username, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accessTokenExists` should not throw unexpected errors when tested with arbitrary input as a username; only specific errors are permissible.


test("fuzz accessTokenCount w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accessTokenCount(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accessTokenCount` processes various inputs without throwing unexpected errors, as expected errors are handled specifically.


test("fuzz accessTokenSelect w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accessTokenSelect(sub, testSecret.id);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The function `accessTokenSelect` should handle various inputs without producing unexpected errors beyond specified HTTP error messages.


test("fuzz accessTokenList w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accessTokenList(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accessTokenList` should handle various inputs without throwing errors, except for specific expected errors, which are filtered by `catchError`.


test("fuzz accessTokenExpire w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accessTokenExpire(sub, testSecret.id);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The `accessTokenExpire` function should either complete without throwing an error or only throw specific expected errors when called with arbitrary inputs.


test("fuzz accessTokenExpire w/ id", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (id) => {
			try {
				await accessTokenExpire(sub, id);
			} catch (e) {
				catchError(id, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accessTokenExpire` should handle any input for `id` either successfully or by throwing one of the expected error messages without crashing.


test("fuzz accessTokenRemove w/ id", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (id) => {
			try {
				await accessTokenRemove(sub, id);
			} catch (e) {
				catchError(id, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The function `accessTokenRemove` should handle a wide range of input IDs, and any exceptions thrown should match expected error messages, otherwise they are logged and rethrown.


test("fuzz webauthnCount w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await webauthnCount(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `webauthnCount` should handle various inputs without throwing unexpected errors, only allowing specified HTTP errors.


test("fuzz webauthnCreate w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await webauthnCreate(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `webauthnCreate` should not throw unexpected errors when called with arbitrary inputs; only specific errors like "400 Bad Request," "401 Unauthorized," "404 Not Found," and "409 Conflict" are acceptable.


test("fuzz webauthnUpate w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await webauthnUpdate(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: Verifies that the `webauthnUpdate` function handles inputs without causing unexpected errors, catching only specified expected errors.


test("fuzz webauthnRemove w/ id", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (id) => {
			try {
				await webauthnRemove(sub, id);
			} catch (e) {
				catchError(id, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The `webauthnRemove` function should handle a wide range of inputs without causing unexpected errors, while expected errors are caught and processed correctly.


test("fuzz recoveryCodesList w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await recoveryCodesList(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The `recoveryCodesList` function should handle any input for the `sub` parameter without producing errors outside a predefined set of expected error messages.


test("fuzz recoveryCodesCreate w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await recoveryCodesCreate(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `recoveryCodesCreate` should handle any input without throwing unexpected errors, logging only inputs that cause errors not included in the predefined set of expected errors.


test("fuzz recoveryCodesUpate w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await recoveryCodesUpdate(sub);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The function `recoveryCodesUpdate` should handle all inputs without throwing unexpected errors, with allowed error messages being "400 Bad Request", "401 Unauthorized", "404 Not Found", and "409 Conflict".


test("fuzz recoveryCodesRemove w/ id", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (id) => {
			try {
				await recoveryCodesRemove(sub, id);
			} catch (e) {
				catchError(id, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `recoveryCodesRemove` is tested to handle a wide range of inputs for `id`, ensuring any errors thrown are expected ("400 Bad Request", "401 Unauthorized", "404 Not Found", "409 Conflict") and handled without crashing.


it("hexToArray -> arrayToHex", () => {
        fc.assert(
            fc.property(hexaString({ minLength: 2 }), string => {
                fc.pre(string.length % 2 == 0);
                assert.equal(arrayToHex(hexToArray(string)), string);
            })
        );
    })

Summary: Conversion from hexadecimal string to array and back to hexadecimal should return the original string when the string length is even.


it("parse remote path", () => {
        fc.assert(
            fc.property(fc.string(), string => {
                const typed = `remote:${string}`;
                assert.deepEqual(parseTypedPath(typed), ["remote", string]);
            })
        );
    })

Summary: `parseTypedPath` splits a typed string into an array containing "remote" and the original string.


it("should create the same object", () => {
      fc.assert(
        fc.property(fc.object(), (obj) => {
          expect(copy(obj)).toEqual(obj);
        })
      );
    })

Summary: The test checks that the function `copy` produces an identical object to the input object.


test("fuzz accountUsernameCreate w/ sub", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (sub) => {
			try {
				await accountUsernameCreate(sub, username);
			} catch (e) {
				catchError(sub, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: The function `accountUsernameCreate` should either execute without error or only throw specific expected errors when given any input for `sub`.


test("fuzz accountUsernameCreate w/ username", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (username) => {
			try {
				await accountUsernameCreate(sub, username);
			} catch (e) {
				catchError(username, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accountUsernameCreate` should not throw unexpected errors when called with arbitrary usernames.


test("fuzz accountUsernameUpdate w/ username", async () => {
	await fc.assert(
		fc.asyncProperty(fc.anything(), async (username) => {
			try {
				await accountUsernameUpdate(sub, username);
			} catch (e) {
				catchError(username, e);
			}
		}),
		{
			numRuns: 100_000,
			verbose: 2,
			examples: [],
		},
	);
})

Summary: `accountUsernameUpdate` should handle a variety of inputs for `username`, with expected errors logged and unexpected ones re-thrown.


test('impl', t => {
  fc.assert(
    fc.property(getArbitrary<ExampleRequest>(getFastChecker()), request => {
      const response = exampleApiImpl(request);
      t.assert(response.messages.length <= request.limit);
      for (const message of response.messages) {
        t.assert(
          isAfter(parseISO(message.date), parseISO(request.after)) ||
            isEqual(parseISO(message.date), parseISO(request.after)),
        );
      }
    }),
  );
})

Summary: The function `exampleApiImpl` should return messages that are within the specified limit of the request and after or equal to the given `after` date.


test.only('i/o boundary', t => {
  fc.assert(
    fc.property(
      fc.oneof(fc.anything(), getArbitrary<ExampleRequest>(getFastChecker())),
      requestAny => {
        const isValidRequest = getValidator()
          .getValidator(getTypeName<ExampleRequest>())
          .is(requestAny);
        if (isValidRequest) {
          t.notThrows(() => {
            const responseAny = exampleApi(requestAny);
            const isValidResponse = getValidator()
              .getValidator(getTypeName<ExampleResponse>())
              .is(responseAny);
            t.true(isValidResponse);
          });
        } else {
          t.throws(() => {
            exampleApi(requestAny);
          });
        }
      },
    ),
  );
})

Summary: The test ensures that valid `ExampleRequest` inputs to `exampleApi` produce valid `ExampleResponse` outputs without exceptions, and invalid inputs result in exceptions.


it('should maintain query structure invariants', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.string({ minLength: 1, maxLength: 1000 }),
          fc.option(fc.record({
            maxResults: fc.integer({ min: 1, max: 100 }),
            walletAddress: fc.string({ minLength: 10, maxLength: 50 })
          })),
          async (query, metadata) => {
            // Mock successful response
            mockFetch.mockResolvedValueOnce({
              ok: true,
              json: async () => ({
                success: true,
                data: [],
                metadata: { creditsUsed: 1, queryTime: 100, resultCount: 0, timestamp: Date.now(), queryId: 'prop-test' }
              })
            } as Response);

            const result = await adapter.search(query, metadata || undefined)();

            // Query should always produce a result (success or failure)
            expect(E.isRight(result)).toBe(true);

            if (E.isRight(result)) {
              // Response should always have success field
              expect(typeof result.right.success).toBe('boolean');

              // If successful, should have data
              if (result.right.success) {
                expect(result.right.data).toBeDefined();
              }
            }
          }
        ),
        { numRuns: 50 }
      );
    })

Summary: Query operations on `HiveIntelligenceAdapter` should always produce a result with a boolean `success` field and, if successful, include a `data` field.


it('should handle rate limiting consistently', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.array(fc.string({ minLength: 1, maxLength: 100 }), { minLength: 1, maxLength: 30 }),
          async (queries) => {
            // Mock responses for all queries
            mockFetch.mockImplementation(() =>
              Promise.resolve({
                ok: true,
                json: async () => ({
                  success: true,
                  data: [],
                  metadata: { creditsUsed: 1, queryTime: 100, resultCount: 0, timestamp: Date.now(), queryId: 'rate-test' }
                })
              } as Response)
            );

            const results = await Promise.all(
              queries.map(query => adapter.search(query)())
            );

            // Should have consistent behavior - either all succeed or some fail due to rate limiting
            const successCount = results.filter(r =>
              E.isRight(r) && r.right.success
            ).length;

            const rateLimitFailures = results.filter(r =>
              E.isLeft(r) && r.left.code === 'RATE_LIMIT_EXCEEDED'
            ).length;

            // Total results should equal input queries
            expect(results.length).toBe(queries.length);

            // Should have some successful results unless all are rate limited
            expect(successCount + rateLimitFailures).toBeLessThanOrEqual(queries.length);
          }
        ),
        { numRuns: 10 }
      );
    })

Summary: The test ensures consistent handling of rate-limiting when processing an array of string queries, verifying that results either succeed or fail due to rate limiting, with the total results matching the number of input queries.


it('should maintain query idempotency', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.string({ minLength: 1, maxLength: 100 }),
          async (query) => {
            // Mock consistent response
            const mockResponse = {
              success: true,
              data: [{ id: 'test-result', title: 'Test' }],
              metadata: { creditsUsed: 1, queryTime: 100, resultCount: 1, timestamp: Date.now(), queryId: 'test' }
            };

            mockFetch.mockResolvedValue(createMockResponse(mockResponse));

            const result1 = await adapter.search(query)();
            const result2 = await adapter.search(query)();

            // Idempotency: same query should produce same result structure
            expect(E.isRight(result1)).toBe(E.isRight(result2));

            if (E.isRight(result1) && E.isRight(result2)) {
              expect(result1.right.success).toBe(result2.right.success);
              // Note: Due to caching, the actual data might be identical
              // but timestamps in metadata might differ
            }
          }
        ),
        { numRuns: 50 }
      );
    })

Summary: Query idempotency should be maintained, ensuring that repeated searches with the same query produce consistent result structures.


it('should preserve query structure invariants', async () => {
      await fc.assert(
        fc.asyncProperty(
          validQueryGenerator,
          async (queryData) => {
            // Mock successful response
            mockFetch.mockResolvedValue(createMockResponse({
              success: true,
              data: [],
              metadata: { creditsUsed: 1, queryTime: 100, resultCount: 0, timestamp: Date.now(), queryId: 'prop-test' }
            }));

            const result = await adapter.search(queryData.query, queryData.metadata || undefined)();

            // Invariant: All queries should produce a result (Either Right or Left)
            expect(E.isRight(result) || E.isLeft(result)).toBe(true);

            if (E.isRight(result)) {
              // Invariant: Response should always have success field
              expect(typeof result.right.success).toBe('boolean');

              // Invariant: If successful, metadata should exist
              if (result.right.success) {
                expect(result.right.metadata).toBeDefined();
              }
            }
          }
        ),
        { numRuns: 100 }
      );
    })

Summary: The property should maintain that all valid queries yield a result as either a `Right` or `Left`, and if `Right`, the result must contain a success field, with metadata present if successful.


it('should enforce rate limiting consistently', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.integer({ min: 1, max: 50 }),
          async (numRequests) => {
            // Mock successful responses
            mockFetch.mockResolvedValue({
              ok: true,
              json: async () => ({
                success: true,
                data: [],
                metadata: { creditsUsed: 1, queryTime: 100, resultCount: 0, timestamp: Date.now(), queryId: 'rate-test' }
              })
            } as Response);

            const promises = Array(numRequests).fill(null).map((_, i) =>
              adapter.search(`test query ${i}`)()
            );

            const results = await Promise.all(promises);

            // Rate limiting property: should not exceed configured limit
            const successfulResults = results.filter(r =>
              E.isRight(r) && r.right.success
            );

            const rateLimitedResults = results.filter(r =>
              E.isLeft(r) && r.left.code === 'RATE_LIMIT_EXCEEDED'
            );

            // If we exceed rate limit, should have failures
            if (numRequests > hiveConfig.rateLimitConfig.maxRequests) {
              expect(rateLimitedResults.length).toBeGreaterThan(0);
            }

            // Total results should equal input
            expect(results.length).toBe(numRequests);
          }
        ),
        { numRuns: 20 }
      );
    })

Summary: The property requires that executing multiple asynchronous requests with `adapter.search` enforces rate limiting, resulting in some requests failing with a `RATE_LIMIT_EXCEEDED` error when the number of requests surpasses the configured limit, while ensuring the total number of results equals the number of input requests.


it('should maintain cache consistency', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.string({ minLength: 1, maxLength: 100 }),
          fc.integer({ min: 2, max: 5 }),
          async (query, repetitions) => {
            let callCount = 0;
            mockFetch.mockImplementation(async () => {
              callCount++;
              return {
                ok: true,
                json: async () => ({
                  success: true,
                  data: [{ id: `result-${callCount}`, title: `Result ${callCount}` }],
                  metadata: { creditsUsed: 1, queryTime: 100, resultCount: 1, timestamp: Date.now(), queryId: `cache-${callCount}` }
                })
              } as Response;
            });

            const results = await Promise.all(
              Array(repetitions).fill(null).map(() => adapter.search(query)())
            );

            // Cache property: identical queries should return consistent results
            const successfulResults = results.filter(r => E.isRight(r) && r.right.success);

            if (successfulResults.length > 1) {
              // If caching is working, should have fewer API calls than requests
              // Note: In a real implementation, we'd need to access cache internals
              // For now, we just verify structural consistency
              expect(successfulResults.length).toBe(repetitions);
            }
          }
        ),
        { numRuns: 20 }
      );
    })

Summary: Identical queries should consistently return the same results, indicating cache consistency, with fewer API calls than requests.


it('should track credit usage monotonically', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.array(fc.integer({ min: 1, max: 5 }), { minLength: 1, maxLength: 10 }),
          async (creditUsages) => {
            let totalUsed = 0;

            for (const creditsUsed of creditUsages) {
              mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                  success: true,
                  data: [],
                  metadata: { creditsUsed, queryTime: 100, resultCount: 0, timestamp: Date.now(), queryId: 'credit-test' }
                })
              } as Response);

              const result = await adapter.search(`test query ${totalUsed}`)();

              if (E.isRight(result) && result.right.success) {
                totalUsed += creditsUsed;

                // Credit usage property: should be monotonically increasing
                expect(result.right.metadata?.creditsUsed).toBe(creditsUsed);
              }
            }

            // Total credits used should equal sum of individual usages
            expect(totalUsed).toBe(creditUsages.reduce((sum, credits) => sum + credits, 0));
          }
        ),
        { numRuns: 30 }
      );
    })

Summary: The test asserts that the credit usage tracked by the `HiveIntelligenceAdapter` increases monotonically with each request, ensuring the total credits used equal the sum of individual credits from multiple requests.


it('should maintain response time consistency', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.integer({ min: 50, max: 500 }),
          async (mockLatency) => {
            mockFetch.mockImplementation(async () => {
              await new Promise(resolve => setTimeout(resolve, mockLatency));
              return {
                ok: true,
                json: async () => ({
                  success: true,
                  data: [],
                  metadata: { creditsUsed: 1, queryTime: mockLatency, resultCount: 0, timestamp: Date.now(), queryId: 'perf-test' }
                })
              } as Response;
            });

            const startTime = Date.now();
            const result = await adapter.search('performance test')();
            const endTime = Date.now();

            const actualLatency = endTime - startTime;

            // Performance property: actual latency should be close to mock latency
            expect(actualLatency).toBeGreaterThanOrEqual(mockLatency);
            expect(actualLatency).toBeLessThan(mockLatency + 1000); // Allow 1s overhead

            if (E.isRight(result) && result.right.success) {
              expect(result.right.metadata?.queryTime).toBe(mockLatency);
            }
          }
        ),
        { numRuns: 20 }
      );
    })

Summary: The adapter should maintain response time consistency by ensuring actual latency closely aligns with the mock latency, with a permissible overhead.


it('should handle concurrent requests without race conditions', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.integer({ min: 2, max: 10 }),
          async (concurrency) => {
            let responseCount = 0;

            mockFetch.mockImplementation(async () => {
              responseCount++;
              return {
                ok: true,
                json: async () => ({
                  success: true,
                  data: [{ id: `result-${responseCount}` }],
                  metadata: { creditsUsed: 1, queryTime: 100, resultCount: 1, timestamp: Date.now(), queryId: `concurrent-${responseCount}` }
                })
              } as Response;
            });

            const promises = Array(concurrency).fill(null).map((_, i) =>
              adapter.search(`concurrent test ${i}`)()
            );

            const results = await Promise.all(promises);

            // Concurrency property: should handle all requests
            expect(results.length).toBe(concurrency);

            // No race conditions: all should be successful or failed consistently
            const successCount = results.filter(r => E.isRight(r) && r.right.success).length;
            const failureCount = results.filter(r => E.isLeft(r)).length;

            expect(successCount + failureCount).toBe(concurrency);
          }
        ),
        { numRuns: 15 }
      );
    })

Summary: The test checks that `adapter.search()` handles a specified number of concurrent requests without race conditions, ensuring all requests either succeed or fail consistently.


it('should satisfy functor laws for response transformations', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.string({ minLength: 1, maxLength: 100 }),
          async (query) => {
            mockFetch.mockResolvedValue({
              ok: true,
              json: async () => ({
                success: true,
                data: [{ id: 'test', title: 'Test Result' }],
                metadata: { creditsUsed: 1, queryTime: 100, resultCount: 1, timestamp: Date.now(), queryId: 'functor-test' }
              })
            } as Response);

            const result = await adapter.search(query)();

            // Functor law: identity
            const identity = <T>(x: T): T => x;
            const identityMapped = pipe(result, E.map(identity));
            expect(identityMapped).toEqual(result);

            // Functor law: composition
            const f = (response: any) => ({ ...response, processed: true });
            const g = (response: any) => ({ ...response, timestamp: Date.now() });

            const composed = pipe(result, E.map(response => g(f(response))));
            const chained = pipe(result, E.map(f), E.map(g));

            // Should have same structure (can't test exact equality due to timestamps)
            expect(E.isRight(composed)).toBe(E.isRight(chained));
          }
        ),
        { numRuns: 30 }
      );
    })

Summary: The property ensures that response transformations applied by the `search` method adhere to functor laws: identity and composition.


it('should maintain credit consumption invariants', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.integer({ min: 0, max: 10 }),
          async (creditsUsed) => {
            mockFetch.mockResolvedValue({
              ok: true,
              json: async () => ({
                success: true,
                data: [],
                metadata: { creditsUsed, queryTime: 100, resultCount: 0, timestamp: Date.now(), queryId: 'credit-invariant' }
              })
            } as Response);

            const result = await adapter.search('credit test')();

            if (E.isRight(result) && result.right.success) {
              // Invariant: Credits used should be non-negative
              expect(result.right.metadata?.creditsUsed).toBeGreaterThanOrEqual(0);

              // Invariant: Credits used should not exceed max per query
              expect(result.right.metadata?.creditsUsed).toBeLessThanOrEqual(hiveConfig.creditConfig.maxCreditsPerQuery);
            }
          }
        ),
        { numRuns: 50 }
      );
    })

Summary: The property ensures that credit consumption invariants are maintained by verifying `creditsUsed` is non-negative and does not exceed the maximum allowed per query in successful search results.


it('should satisfy price impact monotonicity', async () => {
      const priceImpactProperty = fc.property(
        fc.tuple(
          DeFiGenerators.tokenPair(),
          DeFiGenerators.amount(),
          DeFiGenerators.amount()
        ),
        ([tokenPair, amount1, amount2]) => {
          const [tokenIn, tokenOut] = tokenPair;
          const smallerAmount = amount1 < amount2 ? amount1 : amount2;
          const largerAmount = amount1 >= amount2 ? amount1 : amount2;

          // Mock responses for different amounts
          const smallSwapImpact = 0.005; // 0.5%
          const largeSwapImpact = 0.02;  // 2%

          return smallerAmount === largerAmount || smallSwapImpact <= largeSwapImpact;
        }
      );

      await fc.assert(priceImpactProperty, { numRuns: 200 });
    })

Summary: Price impact should be monotonically non-decreasing with increasing trade amounts between token pairs.


it('should complete operations within time bounds', async () => {
      const timeoutProperty = fc.property(
        fc.record({
          operationType: fc.oneof(
            fc.constant('getQuote'),
            fc.constant('getRoutes'),
            fc.constant('estimateGas')
          ),
          complexity: fc.nat({ min: 1, max: 5 }),
          networkLatency: fc.nat({ min: 10, max: 1000 })
        }),
        async (data) => {
          const timeoutLimits = {
            getQuote: 2000,
            getRoutes: 3000,
            estimateGas: 1000
          };

          const expectedTimeout = timeoutLimits[data.operationType] + data.networkLatency;

          // Mock operation with timeout
          const mockOperation = async () => {
            await new Promise(resolve => setTimeout(resolve, data.networkLatency));
            return 'success';
          };

          const start = Date.now();
          await mockOperation();
          const duration = Date.now() - start;

          return duration <= expectedTimeout * 1.1; // 10% tolerance
        }
      );

      await fc.assert(timeoutProperty, { numRuns: 50 });
    })

Summary: Operations should complete within time limits based on their type, complexity, and network latency, allowing a 10% tolerance.


it('should preserve invariants across state transitions', async () => {
      const stateTransitionProperty = fc.property(
        fc.record({
          initialState: fc.record({
            totalLiquidity: DeFiGenerators.amount(),
            activeRoutes: fc.nat({ min: 0, max: 100 }),
            pendingTransactions: fc.nat({ min: 0, max: 50 })
          }),
          action: fc.oneof(
            fc.constant({ type: 'ADD_LIQUIDITY', amount: 1000n }),
            fc.constant({ type: 'REMOVE_LIQUIDITY', amount: 500n }),
            fc.constant({ type: 'EXECUTE_SWAP', routeId: 'route-1' })
          )
        }),
        (data) => {
          // Mock state transition
          let newState = { ...data.initialState };

          switch (data.action.type) {
            case 'ADD_LIQUIDITY':
              newState.totalLiquidity += (data.action as any).amount;
              break;
            case 'REMOVE_LIQUIDITY':
              newState.totalLiquidity -= (data.action as any).amount;
              break;
            case 'EXECUTE_SWAP':
              newState.pendingTransactions += 1;
              break;
          }

          // Invariants:
          // 1. Total liquidity should never be negative
          // 2. Active routes should not exceed maximum
          // 3. Pending transactions should be reasonable

          return newState.totalLiquidity >= 0n &&
                 newState.activeRoutes <= 100 &&
                 newState.pendingTransactions <= 100;
        }
      );

      await fc.assert(stateTransitionProperty, { numRuns: 200 });
    })

Summary: Preserves invariants across state transitions involving total liquidity, active routes, and pending transactions.


test('should autocomplete queries (full)', async () => {
  await fc.assert(
    fc
      .asyncProperty(fc.scheduler({ act }), fc.set(fc.string()), fc.string(1, 10), async (s, allResults, userQuery) => {
        // Arrange
        jest.useFakeTimers();
        suggestionsFor.mockImplementation(
          s.scheduleFunction(async (query) => {
            return allResults.filter((r) => r.includes(query)).slice(0, 10);
          })
        );
        const expectedResults = allResults.filter((r) => r.includes(userQuery));

        // Act
        const { getByRole, queryAllByRole } = render(<DebouncedAutocomplete />);
        s.scheduleSequence(
          [...userQuery].map((c, idx) => ({
            label: `Typing "${c}"`,
            builder: () => userEvent.type(getByRole('textbox'), userQuery.substr(0, idx + 1), { allAtOnce: true }),
          }))
        );
        await waitAllWithTimers(s);

        // Assert
        const displayedSuggestions = queryAllByRole('listitem');
        expect(displayedSuggestions.map((el) => el.textContent)).toEqual(expectedResults);
      })
      .beforeEach(() => {
        jest.clearAllTimers();
        jest.resetAllMocks();
        cleanup();
      })
  );
})

Summary: The `DebouncedAutocomplete` component should return suggestions that match the user query, and these suggestions must be displayed as a list after the user inputs characters in quick succession.


test('should autocomplete queries (full)', async () => {
  await fc.assert(
    fc
      .asyncProperty(fc.scheduler({ act }), fc.set(fc.string()), fc.string(1, 10), async (s, allResults, userQuery) => {
        // Arrange
        suggestionsFor.mockImplementation(
          s.scheduleFunction(async (query) => {
            return allResults.filter((r) => r.includes(query)).slice(0, 10);
          })
        );
        const expectedResults = allResults.filter((r) => r.includes(userQuery));

        // Act
        const { getByRole, queryAllByRole } = render(<Autocomplete />);
        s.scheduleSequence(
          [...userQuery].map((c, idx) => ({
            label: `Typing "${c}"`,
            builder: () => userEvent.type(getByRole('textbox'), userQuery.substr(0, idx + 1), { allAtOnce: true }),
          }))
        );
        await s.waitAll();

        // Assert
        const displayedSuggestions = queryAllByRole('listitem');
        expect(displayedSuggestions.map((el) => el.textContent)).toEqual(expectedResults);
        expect(suggestionsFor).toHaveBeenCalledTimes(userQuery.length);
      })
      .beforeEach(() => {
        jest.resetAllMocks();
        cleanup();
      })
  );
})

Summary: Autocompleting user queries should result in displaying the correct suggestions that match and include those queries, and each character typed should trigger a request for suggestions.


it('queries with `splits: inline` returns only non-parents', async () => {
    await fc.assert(
      fc.asyncProperty(
        arbs.makeTransactionArray({
          splitFreq: 2,
          minLength: 2,
          maxLength: 20
        }),
        async arr => {
          await insertTransactions(arr);

          let { data } = await runQuery(
            query('transactions')
              .filter({ amount: { $lt: 0 } })
              .select('*')
              .options({ splits: 'inline' })
              .serialize()
          );

          expect(data.filter(t => t.is_parent).length).toBe(0);
          expect(data.filter(t => t.tombstone).length).toBe(0);

          let { data: defaultData } = await runQuery(
            query('transactions')
              .filter({ amount: { $lt: 0 } })
              .select('*')
              .serialize()
          );

          // inline should be the default
          expect(defaultData).toEqual(data);
        }
      ),
      { numRuns: 50 }
    );
  })

Summary: Queries with `splits: inline` should return transaction data without parent entries and without tombstones, and this behavior should match the default query result when filtering transactions with negative amounts.


it('aggregate queries work with `splits: grouped`', async () => {
    let payeeIds = ['payee1', 'payee2', 'payee3', 'payee4', 'payee5'];

    await fc.assert(
      fc
        .asyncProperty(
          arbs.makeTransactionArray({ splitFreq: 2, payeeIds, maxLength: 100 }),
          async arr => {
            await insertTransactions(arr, payeeIds);

            let aggQuery = query('transactions')
              .filter({
                $or: [{ amount: { $lt: -5 } }, { amount: { $gt: -2 } }],
                'payee.name': { $gt: '' }
              })
              .options({ splits: 'grouped' })
              .calculate({ $sum: '$amount' });

            let { data } = await runQuery(aggQuery.serialize());

            let sum = arr.reduce((sum, trans) => {
              let amount = trans.amount || 0;
              let matched = (amount < -5 || amount > -2) && trans.payee != null;
              if (!trans.tombstone && !trans.is_parent && matched) {
                return sum + amount;
              }
              return sum;
            }, 0);

            expect(data).toBe(sum);
          }
        )
        .beforeEach(() => {
          setClock(null);
          setSyncingMode('import');
          return db.execQuery(`
            DELETE FROM transactions;
            DELETE FROM payees;
            DELETE FROM payee_mapping;
          `);
        })
    );
  })

Summary: Aggregate query with `splits: grouped` should accurately calculate the sum of transaction amounts for transactions that meet specified filter conditions.


test('Integer should concatenate with a string', () => {
    fc.assert(
      fc.property(
        fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
        // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
        num => 'string' + int(num) + 'str' === 'string' + int(num).toString() + 'str'
      )
    )
  })

Summary: Concatenating an `Integer` with strings produces the same result as concatenating its string representation.


test('Integer should be able to use + operator as bigint', () => {
    fc.assert(
      fc.property(
        fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
        fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
        (num1, num2) =>
          // @ts-expect-error
          // eslint-disable-next-line  @typescript-eslint/restrict-plus-operands
          num1 + int(num2) === num1 + num2 &&
          // @ts-expect-error
          // eslint-disable-next-line  @typescript-eslint/restrict-plus-operands
          int(num1) + num2 === num1 + num2 &&
          // @ts-expect-error
          // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
          int(num1) + int(num2) === num1 + num2
      ))
  })

Summary: Integer addition with the `+` operator should behave identically to `bigint` addition for values within the safe range.


test('Integer should be able to use - operator as bigint', () => {
    fc.assert(
      fc.property(
        fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
        fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
        (num1, num2) =>
          // @ts-expect-error
          num1 - int(num2) === num1 - num2 &&
          // @ts-expect-error
          int(num1) - num2 === num1 - num2 &&
          // @ts-expect-error
          int(num1) - int(num2) === num1 - num2
      ))
  })

Summary: The `Integer` type should correctly use the minus operator as `bigint`, ensuring consistent subtraction results across combinations of `Integer` and `bigint` values.


test('Integer should be able to use * operator as bigint', () => {
    fc.assert(
      fc.property(
        fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
        fc.bigInt({ max: Integer.MAX_SAFE_VALUE.toBigInt(), min: Integer.MIN_SAFE_VALUE.toBigInt() }),
        (num1, num2) =>
          // @ts-expect-error
          num1 * int(num2) === num1 * num2 &&
          // @ts-expect-error
          int(num1) * num2 === num1 * num2 &&
          // @ts-expect-error
          int(num1) * int(num2) === num1 * num2
      ))
  })

Summary: The property checks that using the `*` operator between integers and their `Integer` representations behaves identically to using the operator with regular bigints.


test('int(number) should be reversed by Integer.toNumber', () => {
    fc.assert(fc.property(fc.integer(), num => num === int(num).toNumber()))
  })

Summary: Converting a number to an integer using `int` and then back to a number using `Integer.toNumber` results in the original number.


test('int(Integer) should be equal Integer', () => {
    fc.assert(fc.property(arbitraryInteger(), integer => integer === int(integer)))
  })

Summary: `int(Integer)` should return an `Integer` equal to the original input `Integer`.


test('Integer.add should be Commutative', () => {
    fc.assert(fc.property(arbitraryInteger(), arbitraryInteger(),
      (a, b) => a.add(b).equals(b.add(a))))
  })

Summary: `Integer.add` operation commutes, meaning `a.add(b)` equals `b.add(a)`.


test('Integer.add should be Associative', () => {
    fc.assert(fc.property(arbitraryInteger(), arbitraryInteger(), arbitraryInteger(),
      (a, b, c) => a.add(b.add(c)).equals(a.add(b).add(c))))
  })

Summary: The `add` function of the `Integer` class should be associative.


test('Integer.multiply should be Associative', () => {
    fc.assert(fc.property(arbitraryInteger(), arbitraryInteger(), arbitraryInteger(),
      (a, b, c) => a.multiply(b.multiply(c)).equals(a.multiply(b).multiply(c))))
  })

Summary: The multiplication of `Integer` objects should be associative, meaning the result should remain the same regardless of how the operands are grouped.


test('Integer.add should have 0 as identity', () => {
    fc.assert(fc.property(arbitraryInteger(), (a) => a.add(0).equals(a)))
  })

Summary: Adding 0 to an `Integer` should result in the same `Integer`.


test('Integer.subtract should have 0 as identity', () => {
    fc.assert(fc.property(arbitraryInteger(), (a) => a.subtract(0).equals(a)))
  })

Summary: `Integer.subtract` returns the original integer when subtracting zero.


test('Integer.equals should return true if a - b is ZERO', () => {
    fc.assert(fc.property(arbitraryInteger(), arbitraryInteger(),
      (a, b) => a.subtract(b).isZero() ? a.equals(b) : !a.equals(b)))
  })

Summary: `Integer.equals` returns true if subtracting one instance from another results in zero.


test('Integer.greaterThan should return true if a - b is positive', () => {
      fc.assert(fc.property(
        arbitrarySameSignIntegers(),
        ({ a, b }) => a.subtract(b).isPositive() ? a.greaterThan(b) : !a.greaterThan(b)))
    })

Summary: `Integer.greaterThan` returns true if and only if the result of `a.subtract(b)` is positive for integers with the same sign.


test('Integer.greaterThan should return true if a is positive', () => {
      fc.assert(fc.property(
        arbitraryDiffSignIntegers(),
        ({ a, b }) => a.isPositive() ? a.greaterThan(b) : !a.greaterThan(b)))
    })

Summary: `Integer.greaterThan` returns true when a positive integer is compared to an integer of opposite sign, otherwise returns false.


it('should round up sub milliseconds transaction timeouts', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc.float({ min: 0, noNaN: true }),
          async (timeout: number) => {
            const connection = mockBeginWithSuccess(newFakeConnection())

            const { session } = setupSession({
              connection,
              beginTx: false,
              database: 'neo4j'
            })

            await session.beginTransaction({ timeout })

            expect(connection.seenBeginTransaction[0][0].txConfig.timeout)
              .toEqual(int(Math.ceil(timeout)))
          }
        )
      )
    })

Summary: Sub-millisecond transaction timeouts should be rounded up to the nearest whole number.


it('should log when a timeout is configured with sub milliseconds', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc
            .float({ min: 0, noNaN: true })
            .filter((timeout: number) => !Number.isInteger(timeout)),
          async (timeout: number) => {
            const connection = mockBeginWithSuccess(newFakeConnection())

            const { session, loggerFunction } = setupSession({
              connection,
              beginTx: false,
              database: 'neo4j'
            })

            await session.beginTransaction({ timeout })

            expect(loggerFunction).toBeCalledWith(
              'info',
              `Transaction timeout expected to be an integer, got: ${timeout}. The value will be rounded up.`
            )
          }
        )
      )
    })

Summary: Logging occurs when a transaction timeout is set with a non-integer sub-millisecond value, indicating it will be rounded up.


it('should not log a warning for timeout configurations without sub milliseconds', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc.nat(),
          async (timeout: number) => {
            const connection = mockBeginWithSuccess(newFakeConnection())

            const { session, loggerFunction } = setupSession({
              connection,
              beginTx: false,
              database: 'neo4j'
            })

            await session.beginTransaction({ timeout })

            expect(loggerFunction).not.toBeCalledWith(
              'info',
              expect.any(String)
            )
          }
        )
      )
    })

Summary: No warning log should be produced when beginning a transaction with a timeout configuration that does not include sub-millisecond precision.


it('should round up sub milliseconds transaction timeouts', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc.float({ min: 0, noNaN: true }),
          async (timeout: number) => {
            const connection = mockBeginWithSuccess(newFakeConnection())
            const session = newSessionWithConnection(connection, false, FETCH_ALL)
            // @ts-expect-error
            jest.spyOn(Transaction.prototype, 'run').mockImplementation(async () => await Promise.resolve())
            const query = 'RETURN $a'
            const params = { a: 1 }

            await execute(session)(async (tx: ManagedTransaction) => {
              await tx.run(query, params)
            }, { timeout })

            expect(connection.seenBeginTransaction[0][0].txConfig.timeout)
              .toEqual(int(Math.ceil(timeout)))
          }
        )
      )
    })

Summary: Transaction timeout values with sub-millisecond precision are rounded up to the nearest whole number in the configuration.


it('should log a warning for timeout configurations with sub milliseconds', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc
            .float({ min: 0, noNaN: true })
            .filter((timeout: number) => !Number.isInteger(timeout)),
          async (timeout: number) => {
            const connection = mockBeginWithSuccess(newFakeConnection())
            const { session, loggerFunction } = setupSession({
              connection,
              beginTx: false,
              fetchSize: FETCH_ALL
            })

            // @ts-expect-error
            jest.spyOn(Transaction.prototype, 'run').mockImplementation(async () => await Promise.resolve())
            const query = 'RETURN $a'
            const params = { a: 1 }

            await execute(session)(async (tx: ManagedTransaction) => {
              await tx.run(query, params)
            }, { timeout })

            expect(loggerFunction).toBeCalledWith(
              'info',
              `Transaction timeout expected to be an integer, got: ${timeout}. The value will be rounded up.`
            )
          }
        )
      )
    })

Summary: Logs a warning message when a transaction timeout is configured with a non-integer value, indicating that the value will be rounded up.


it('should not log a warning for timeout configurations without sub milliseconds', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc.nat(),
          async (timeout: number) => {
            const connection = mockBeginWithSuccess(newFakeConnection())
            const { session, loggerFunction } = setupSession({
              connection,
              beginTx: false,
              fetchSize: FETCH_ALL
            })

            // @ts-expect-error
            jest.spyOn(Transaction.prototype, 'run').mockImplementation(async () => await Promise.resolve())
            const query = 'RETURN $a'
            const params = { a: 1 }

            await execute(session)(async (tx: ManagedTransaction) => {
              await tx.run(query, params)
            }, { timeout })

            expect(loggerFunction).not.toBeCalledWith(
              'info',
              expect.any(String)
            )
          }
        )
      )
    })

Summary: A session should not log an "info" level warning for timeout configurations when no sub-millisecond values are present.


it('should round up sub milliseconds transaction timeouts', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc.float({ min: 0, noNaN: true }),
          async (timeout: number) => {
            const connection = newFakeConnection()

            const { session } = setupSession({
              connection,
              beginTx: false,
              database: 'neo4j'
            })

            await session.run('query', {}, { timeout })

            expect(connection.seenProtocolOptions[0].txConfig.timeout)
              .toEqual(int(Math.ceil(timeout)))
          }
        )
      )
    })

Summary: Transaction timeouts with sub-millisecond precision should be rounded up to the nearest millisecond integer when applied in a session.


it('should log a warning for timeout configurations with sub milliseconds', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc
            .float({ min: 0, noNaN: true })
            .filter((timeout: number) => !Number.isInteger(timeout)),
          async (timeout: number) => {
            const connection = newFakeConnection()

            const { session, loggerFunction } = setupSession({
              connection,
              beginTx: false,
              database: 'neo4j'
            })

            await session.run('query', {}, { timeout })

            expect(loggerFunction).toBeCalledWith(
              'info',
              `Transaction timeout expected to be an integer, got: ${timeout}. The value will be rounded up.`
            )
          }
        )
      )
    })

Summary: A warning should be logged when a session is run with a timeout configuration that has a sub-millisecond value, indicating it will be rounded up.


it('should not log a warning for timeout configurations without sub milliseconds', async () => {
      return await fc.assert(
        fc.asyncProperty(
          fc.nat(),
          async (timeout: number) => {
            const connection = newFakeConnection()

            const { session, loggerFunction } = setupSession({
              connection,
              beginTx: false,
              database: 'neo4j'
            })

            await session.run('query', {}, { timeout })

            expect(loggerFunction).not.toBeCalledWith(
              'info',
              expect.any(String)
            )
          }
        )
      )
    })

Summary: No warning should be logged for timeout configurations that do not include sub-millisecond values.


it('should handle return arbitrary integer as it is', () => {
      return fc.assert(
        fc.property(
          fc.integer(),
          value => {
            const rawProfilePlan = {
              [field]: value
            }

            const profilePlan = new ProfiledPlan(rawProfilePlan)

            return profilePlan[field] === value
          }
        )
      )
    })

Summary: `ProfiledPlan` retains arbitrary integer values as they are in the specified field.


it('should handle return arbitrary integer as it is', () => {
      return fc.assert(
        fc.property(
          fc.integer(),
          value => {
            const stats = {
              [rawField]: value
            }

            const queryStatistics = new QueryStatistics(stats)

            return queryStatistics.updates()[field] === value
          }
        )
      )
    })

Summary: `QueryStatistics` correctly returns arbitrary integer values as they are from the updates method.


it('should handle Integer with arbitrary integer', () => {
      return fc.assert(
        fc.property(
          fc.integer().map(value => [int(value), value]),
          ([value, expectedValue]) => {
            const stats = {
              [rawField]: value
            }

            const queryStatistics = new QueryStatistics(stats)

            return queryStatistics.updates()[field] === expectedValue
          }
        )
      )
    })

Summary: `QueryStatistics` correctly retrieves the original integer value from the statistics object.


it("should fail to cast non-booleans", () => {
      expect.assertions(100);
      fc.assert(
        fc.property(
          fc.anything().filter((input) => typeof input !== "boolean"),
          (input) => {
            expect(castBoolean(input)).toStrictEqual({
              status: "failure",
              expected: "boolean",
              actual: input
            });
          }
        )
      );
    })

Summary: Casting non-boolean inputs results in a failure status, indicating the expected type as "boolean" and the actual input type.


it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
      fc.assert(
        fc.property(fc.date(), date => {
          const object = DateTime.fromStandardDate(date)
          const buffer = alloc(256)
          const loggerFunction = jest.fn()
          const protocol = new BoltProtocolV5x6(
            new utils.MessageRecordingConnection(),
            buffer,
            {
              disableLosslessIntegers: true
            },
            undefined,
            new Logger('debug', loggerFunction)
          )

          const packable = protocol.packable(object)

          expect(packable).not.toThrow()

          buffer.reset()

          const unpacked = protocol.unpack(buffer)

          expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

          expect(unpacked).toEqual(object)
        })
      )
    })

Summary: Packing and unpacking `DateTimeWithZoneIdAndNoOffset` correctly maintains the original object, including a defined `timeZoneOffsetSeconds`.


it('should pack and unpack DateTimeWithOffset', () => {
      fc.assert(
        fc.property(
          fc.date({
            min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
            max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
          }),
          fc.integer({ min: 0, max: 999_999 }),
          utils.arbitraryTimeZoneId(),
          (date, nanoseconds, timeZoneId) => {
            const object = new DateTime(
              date.getUTCFullYear(),
              date.getUTCMonth() + 1,
              date.getUTCDate(),
              date.getUTCHours(),
              date.getUTCMinutes(),
              date.getUTCSeconds(),
              date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
              undefined,
              timeZoneId
            )
            const buffer = alloc(256)
            const loggerFunction = jest.fn()
            const protocol = new BoltProtocolV5x3(
              new utils.MessageRecordingConnection(),
              buffer,
              {
                disableLosslessIntegers: true
              },
              undefined,
              new Logger('debug', loggerFunction)
            )

            const packable = protocol.packable(object)

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

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            const unpackedDateTimeWithoutOffset = new DateTime(
              unpacked.year,
              unpacked.month,
              unpacked.day,
              unpacked.hour,
              unpacked.minute,
              unpacked.second,
              unpacked.nanosecond,
              undefined,
              unpacked.timeZoneId
            )

            expect(unpackedDateTimeWithoutOffset).toEqual(object)
          })
      )
    })

Summary: Packing and unpacking of `DateTimeWithOffset` should maintain the integrity of the original date-time object, including the handling of ambiguous times and issuing warnings when the `timeZoneOffsetSeconds` is undefined.


it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
      fc.assert(
        fc.property(fc.date(), date => {
          const object = DateTime.fromStandardDate(date)
          const buffer = alloc(256)
          const loggerFunction = jest.fn()
          const protocol = new BoltProtocolV5x3(
            new utils.MessageRecordingConnection(),
            buffer,
            {
              disableLosslessIntegers: true
            },
            undefined,
            new Logger('debug', loggerFunction)
          )

          const packable = protocol.packable(object)

          expect(packable).not.toThrow()

          buffer.reset()

          const unpacked = protocol.unpack(buffer)

          expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

          expect(unpacked).toEqual(object)
        })
      )
    })

Summary: Packing and unpacking `DateTimeWithZoneIdAndNoOffset` should maintain data integrity, ensuring the unpacked object matches the original.


it('should pack and unpack DateTimeWithOffset', () => {
      fc.assert(
        fc.property(
          fc.date({
            min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
            max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
          }),
          fc.integer({ min: 0, max: 999_999 }),
          utils.arbitraryTimeZoneId(),
          (date, nanoseconds, timeZoneId) => {
            const object = new DateTime(
              date.getUTCFullYear(),
              date.getUTCMonth() + 1,
              date.getUTCDate(),
              date.getUTCHours(),
              date.getUTCMinutes(),
              date.getUTCSeconds(),
              date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
              undefined,
              timeZoneId
            )
            const buffer = alloc(256)
            const loggerFunction = jest.fn()
            const protocol = new BoltProtocolV6x0(
              new utils.MessageRecordingConnection(),
              buffer,
              {
                disableLosslessIntegers: true
              },
              undefined,
              new Logger('debug', loggerFunction)
            )

            const packable = protocol.packable(object)

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

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            const unpackedDateTimeWithoutOffset = new DateTime(
              unpacked.year,
              unpacked.month,
              unpacked.day,
              unpacked.hour,
              unpacked.minute,
              unpacked.second,
              unpacked.nanosecond,
              undefined,
              unpacked.timeZoneId
            )

            expect(unpackedDateTimeWithoutOffset).toEqual(object)
          })
      )
    })

Summary: Packing and unpacking `DateTimeWithOffset` should correctly produce a `DateTime` object, with a warning for missing `"timeZoneOffsetSeconds"` and ensure the unpacked object matches the original.


it('should pack and unpack DateTimeWithOffset', () => {
      fc.assert(
        fc.property(
          fc.date({
            min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
            max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
          }),
          fc.integer({ min: 0, max: 999_999 }),
          utils.arbitraryTimeZoneId(),
          (date, nanoseconds, timeZoneId) => {
            const object = new DateTime(
              date.getUTCFullYear(),
              date.getUTCMonth() + 1,
              date.getUTCDate(),
              date.getUTCHours(),
              date.getUTCMinutes(),
              date.getUTCSeconds(),
              date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
              undefined,
              timeZoneId
            )
            const buffer = alloc(256)
            const loggerFunction = jest.fn()
            const protocol = new BoltProtocolV5x8(
              new utils.MessageRecordingConnection(),
              buffer,
              {
                disableLosslessIntegers: true
              },
              undefined,
              new Logger('debug', loggerFunction)
            )

            const packable = protocol.packable(object)

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

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            const unpackedDateTimeWithoutOffset = new DateTime(
              unpacked.year,
              unpacked.month,
              unpacked.day,
              unpacked.hour,
              unpacked.minute,
              unpacked.second,
              unpacked.nanosecond,
              undefined,
              unpacked.timeZoneId
            )

            expect(unpackedDateTimeWithoutOffset).toEqual(object)
          })
      )
    })

Summary: Packing and unpacking of `DateTimeWithOffset` should preserve the original `DateTime` properties, while ensuring a warning is logged for potential ambiguities when the `timeZoneOffsetSeconds` is absent, and correctly restoring it upon unpacking.


it('should pack and unpack DateTimeWithOffset', () => {
      fc.assert(
        fc.property(
          fc.date({
            min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
            max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
          }),
          fc.integer({ min: 0, max: 999_999 }),
          utils.arbitraryTimeZoneId(),
          (date, nanoseconds, timeZoneId) => {
            const object = new DateTime(
              date.getUTCFullYear(),
              date.getUTCMonth() + 1,
              date.getUTCDate(),
              date.getUTCHours(),
              date.getUTCMinutes(),
              date.getUTCSeconds(),
              date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
              undefined,
              timeZoneId
            )
            const buffer = alloc(256)
            const loggerFunction = jest.fn()
            const protocol = new BoltProtocolV5x2(
              new utils.MessageRecordingConnection(),
              buffer,
              {
                disableLosslessIntegers: true
              },
              undefined,
              new Logger('debug', loggerFunction)
            )

            const packable = protocol.packable(object)

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

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            const unpackedDateTimeWithoutOffset = new DateTime(
              unpacked.year,
              unpacked.month,
              unpacked.day,
              unpacked.hour,
              unpacked.minute,
              unpacked.second,
              unpacked.nanosecond,
              undefined,
              unpacked.timeZoneId
            )

            expect(unpackedDateTimeWithoutOffset).toEqual(object)
          })
      )
    })

Summary: Packing and unpacking `DateTimeWithOffset` should correctly handle dates within a specified range, generating a warning for missing time zone offsets and ensuring the unpacked object matches the original.


it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
      fc.assert(
        fc.property(fc.date(), date => {
          const object = DateTime.fromStandardDate(date)
          const buffer = alloc(256)
          const loggerFunction = jest.fn()
          const protocol = new BoltProtocolV5x2(
            new utils.MessageRecordingConnection(),
            buffer,
            {
              disableLosslessIntegers: true
            },
            undefined,
            new Logger('debug', loggerFunction)
          )

          const packable = protocol.packable(object)

          expect(packable).not.toThrow()

          buffer.reset()

          const unpacked = protocol.unpack(buffer)

          expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

          expect(unpacked).toEqual(object)
        })
      )
    })

Summary: The test ensures that `BoltProtocolV5x2` can correctly pack and unpack `DateTimeWithZoneIdAndNoOffset`, maintaining the original object's properties, including a defined time zone offset.


it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
      fc.assert(
        fc.property(fc.date(), date => {
          const object = DateTime.fromStandardDate(date)
          const buffer = alloc(256)
          const loggerFunction = jest.fn()
          const protocol = new BoltProtocolV5x1(
            new utils.MessageRecordingConnection(),
            buffer,
            {
              disableLosslessIntegers: true
            },
            undefined,
            new Logger('debug', loggerFunction)
          )

          const packable = protocol.packable(object)

          expect(packable).not.toThrow()

          buffer.reset()

          const unpacked = protocol.unpack(buffer)

          expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

          expect(unpacked).toEqual(object)
        })
      )
    })

Summary: Packing and unpacking a `DateTimeWithZoneIdAndNoOffset` should maintain the integrity of the original object and define `timeZoneOffsetSeconds` after unpacking.


it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
        fc.assert(
          fc.property(fc.date(), date => {
            const object = DateTime.fromStandardDate(date)

            buffer.reset()

            const packable = protocol.packable(object)

            expect(packable).not.toThrow()

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            expect(unpacked).toEqual(object)
          })
        )
      })

Summary: Ensures that `DateTime` objects, when packed and unpacked, maintain their integrity and contain defined `timeZoneOffsetSeconds`.


it('should pack and unpack DateTimeWithOffset', () => {
      fc.assert(
        fc.property(
          fc.date({
            min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
            max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
          }),
          fc.integer({ min: 0, max: 999_999 }),
          utils.arbitraryTimeZoneId(),
          (date, nanoseconds, timeZoneId) => {
            const object = new DateTime(
              date.getUTCFullYear(),
              date.getUTCMonth() + 1,
              date.getUTCDate(),
              date.getUTCHours(),
              date.getUTCMinutes(),
              date.getUTCSeconds(),
              date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
              undefined,
              timeZoneId
            )
            const buffer = alloc(256)
            const loggerFunction = jest.fn()
            const protocol = new BoltProtocolV5x0(
              new utils.MessageRecordingConnection(),
              buffer,
              {
                disableLosslessIntegers: true
              },
              undefined,
              new Logger('debug', loggerFunction)
            )

            const packable = protocol.packable(object)

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

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            const unpackedDateTimeWithoutOffset = new DateTime(
              unpacked.year,
              unpacked.month,
              unpacked.day,
              unpacked.hour,
              unpacked.minute,
              unpacked.second,
              unpacked.nanosecond,
              undefined,
              unpacked.timeZoneId
            )

            expect(unpackedDateTimeWithoutOffset).toEqual(object)
          })
      )
    })

Summary: Packing and unpacking `DateTimeWithOffset` should preserve all properties, including creating warnings for missing offsets and ensuring the unpacked object matches the original.


it('should pack and unpack DateTimeWithOffset', () => {
      fc.assert(
        fc.property(
          fc.date({
            min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
            max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
          }),
          fc.integer({ min: 0, max: 999_999 }),
          utils.arbitraryTimeZoneId(),
          (date, nanoseconds, timeZoneId) => {
            const object = new DateTime(
              date.getUTCFullYear(),
              date.getUTCMonth() + 1,
              date.getUTCDate(),
              date.getUTCHours(),
              date.getUTCMinutes(),
              date.getUTCSeconds(),
              date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
              undefined,
              timeZoneId
            )
            const buffer = alloc(256)
            const loggerFunction = jest.fn()
            const protocol = new BoltProtocolV5x5(
              new utils.MessageRecordingConnection(),
              buffer,
              {
                disableLosslessIntegers: true
              },
              undefined,
              new Logger('debug', loggerFunction)
            )

            const packable = protocol.packable(object)

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

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            const unpackedDateTimeWithoutOffset = new DateTime(
              unpacked.year,
              unpacked.month,
              unpacked.day,
              unpacked.hour,
              unpacked.minute,
              unpacked.second,
              unpacked.nanosecond,
              undefined,
              unpacked.timeZoneId
            )

            expect(unpackedDateTimeWithoutOffset).toEqual(object)
          })
      )
    })

Summary: Ensures that `DateTimeWithOffset` objects are correctly packed and unpacked by `BoltProtocolV5x5`, with a warning issued for missing `timeZoneOffsetSeconds`, and verifies the equality of the original and unpacked objects.


it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
      fc.assert(
        fc.property(fc.date(), date => {
          const object = DateTime.fromStandardDate(date)
          const buffer = alloc(256)
          const loggerFunction = jest.fn()
          const protocol = new BoltProtocolV5x5(
            new utils.MessageRecordingConnection(),
            buffer,
            {
              disableLosslessIntegers: true
            },
            undefined,
            new Logger('debug', loggerFunction)
          )

          const packable = protocol.packable(object)

          expect(packable).not.toThrow()

          buffer.reset()

          const unpacked = protocol.unpack(buffer)

          expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

          expect(unpacked).toEqual(object)
        })
      )
    })

Summary: Packing and unpacking a `DateTimeWithZoneIdAndNoOffset` should consistently recreate the original object with the same properties including a defined time zone offset.


it('should pack and unpack DateTimeWithOffset', () => {
      fc.assert(
        fc.property(
          fc.date({
            min: temporalUtil.newDate(utils.MIN_UTC_IN_MS + utils.ONE_DAY_IN_MS),
            max: temporalUtil.newDate(utils.MAX_UTC_IN_MS - utils.ONE_DAY_IN_MS)
          }),
          fc.integer({ min: 0, max: 999_999 }),
          utils.arbitraryTimeZoneId(),
          (date, nanoseconds, timeZoneId) => {
            const object = new DateTime(
              date.getUTCFullYear(),
              date.getUTCMonth() + 1,
              date.getUTCDate(),
              date.getUTCHours(),
              date.getUTCMinutes(),
              date.getUTCSeconds(),
              date.getUTCMilliseconds() * 1_000_000 + nanoseconds,
              undefined,
              timeZoneId
            )
            const buffer = alloc(256)
            const loggerFunction = jest.fn()
            const protocol = new BoltProtocolV5x4(
              new utils.MessageRecordingConnection(),
              buffer,
              {
                disableLosslessIntegers: true
              },
              undefined,
              new Logger('debug', loggerFunction)
            )

            const packable = protocol.packable(object)

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

            buffer.reset()

            const unpacked = protocol.unpack(buffer)

            expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

            const unpackedDateTimeWithoutOffset = new DateTime(
              unpacked.year,
              unpacked.month,
              unpacked.day,
              unpacked.hour,
              unpacked.minute,
              unpacked.second,
              unpacked.nanosecond,
              undefined,
              unpacked.timeZoneId
            )

            expect(unpackedDateTimeWithoutOffset).toEqual(object)
          })
      )
    })

Summary: Packing and unpacking a `DateTime` object with a time zone ID should correctly handle and log warnings for objects without a `timeZoneOffsetSeconds`, ensuring the unpacked object matches the original.


it('should pack and unpack DateTimeWithZoneIdAndNoOffset', () => {
      fc.assert(
        fc.property(fc.date(), date => {
          const object = DateTime.fromStandardDate(date)
          const buffer = alloc(256)
          const loggerFunction = jest.fn()
          const protocol = new BoltProtocolV5x4(
            new utils.MessageRecordingConnection(),
            buffer,
            {
              disableLosslessIntegers: true
            },
            undefined,
            new Logger('debug', loggerFunction)
          )

          const packable = protocol.packable(object)

          expect(packable).not.toThrow()

          buffer.reset()

          const unpacked = protocol.unpack(buffer)

          expect(unpacked.timeZoneOffsetSeconds).toBeDefined()

          expect(unpacked).toEqual(object)
        })
      )
    })

Summary: Packing and unpacking a `DateTimeWithZoneIdAndNoOffset` must correctly handle date objects, ensuring the original and unpacked values are equal, including a defined `timeZoneOffsetSeconds`.


t.test('asIntN', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.integer({ min: 0, max: N }), (n, m) => {
      t.equal(t_asIntN(m, n), BigInt.asIntN(m, n));
    }),
    {
      examples: [
        [0n, 0],
        [1n, 0],
        [-1n, 0],
        [1n, 1],
        [-1n, 1]
      ]
    }
  );

  t.end();
})

Summary: `asIntN` function should return the same result as `BigInt.asIntN` for a given bit-width and big integer, including specific example cases.


t.test('isqrt', t => {
  fc.assert(
    fc.property(fc.integer({ min: 1 }), n => {
      t.equal(t_sqrt(n), BigIntMath.sqrt(n));
    })
  );

  // // Identity
  // fc.assert(
  //   fc.property(fc.bigInt(1n, 2n**64n), n => {
  //     t.equal(t_sqrt(n**2n), n);
  //   })
  // );

  t.end();
})

Summary: The `t_sqrt` function should produce the same integer square root as `BigIntMath.sqrt` for integers greater than or equal to 1.


t.test('log10', t => {
  fc.assert(
    fc.property(fc.bigInt({ min: 1n, max: M }), n => {
      t.equal(t_log10(n), BigIntMath.log(10, n));
    })
  );

  // Identity
  fc.assert(
    fc.property(fc.bigInt(1n, 1000n), n => {
      t.equal(t_log10(10n ** n), n);
    })
  );

  t.end();
})

Summary: `log10` function produces the expected result when computing the logarithm base 10 of given big integers, and for powers of ten, the logarithm correctly returns the exponent.


t.test('pow', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigInt(0n, 2n ** 4n), (n, m) => {
      t.equal(t_pow(n, m), n ** m);
    }),
    {
      examples: [
        [0n, 0n],
        [1n, 1n],
        [2n, 2n],
        [0xdeadbeefn, 1n]
      ]
    }
  );

  t.end();
})

Summary: The function `t_pow` should correctly compute the power of a big integer `n` raised to another big integer `m`, matching the result of `n ** m`.


t.test('powMod', t => {
  fc.assert(
    fc.property(
      fc.bigIntN(N),
      fc.bigInt(0n, 2n ** 8n),
      fc.bigInt(0n, 2n ** 256n),
      (x, n, m) => {
        if (m === 0n) m++;
        t.equal(t_powMod(x, n, m), BigIntMath.mod(x ** n, m));
      }
    )
  );

  t.end();
})

Summary: The function `t_powMod` should match the result of `BigIntMath.mod(x ** n, m)` for given big integers `x`, `n`, and `m`, with `m` adjusted to be non-zero when necessary.


t.test('identites', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), n => {
      t.equal(t_pow(n, 0n), 1n);
      t.equal(t_pow(n, 1n), n);
    })
  );

  // a^*(m + n) = a^m * a^n
  // (a^m)^n = a^(m * n)

  t.end();
})

Summary: For any big integer \( n \), raising it to the power of 0 results in 1, and raising it to the power of 1 results in \( n \).


t.test("Kunth's Test", t => {
  const b = 10;
  const bm1 = `9`;
  const bm2 = `8`;

  fc.assert(
    fc.property(
      fc.integer({ min: 2, max: 8 }),
      fc.integer({ min: 1, max: 8 }),
      (n, m) => {
        n = n + m; // n > m

        const r = [
          bm1.repeat(m - 1),
          bm2,
          bm1.repeat(n - m),
          '0'.repeat(m - 1),
          1
        ].join('');

        const tm = mpz.sub(mpz.pow(from(b), from(m)), from(1));
        const tn = mpz.sub(mpz.pow(from(b), from(n)), from(1));

        t.equal(to(mpz.mul(tm, tn)), BigInt(r));
      }
    )
  );

  t.end();
})

Summary: Kunth's test verifies that multiplying the results of two specific mpz operations, based on powers and subtractions with base `b`, matches the expected concatenated string pattern converted to a BigInt.


t.test('toString(-16)', t => {
    t.equal(t_string('0', -16), '0');
    t.equal(t_string('-0xbeef', -16), '-BEEF');
    t.equal(t_string('0xdeadbeef', -16), 'DEADBEEF');

    fc.assert(
      fc.property(fc.bigIntN(N), n => {
        t.equal(t_string(n, -16), n.toString(16).toUpperCase());
      })
    );

    t.end();
  })

Summary: The function `t_string` should correctly convert integers to uppercase hexadecimal strings when using a base of -16.


Summary: The `t_string` function correctly converts integers, including hexadecimal, to their binary string representation.


t.test('toHex', t => {
  t.equal(t_hex('0'), '0x0');

  t.equal(t_hex('3'), '0x3');
  t.equal(t_hex('0xdeadbeef'), '0xdeadbeef');
  t.equal(t_hex('3735928559'), '0xdeadbeef');
  t.equal(t_hex('0xdeadbeefdeadbeef'), '0xdeadbeefdeadbeef');
  t.equal(
    t_hex('0xdeadbeefdeadbeefdeadbeefdeadbeef'),
    '0xdeadbeefdeadbeefdeadbeefdeadbeef'
  );

  t.equal(t_hex(-3), '-0x3');
  t.equal(t_hex('-0xdeadbeef'), '-0xdeadbeef');
  t.equal(t_hex('-3735928559'), '-0xdeadbeef');
  t.equal(t_hex('-0xdeadbeefdeadbeef'), '-0xdeadbeefdeadbeef');
  t.equal(
    t_hex('-0xdeadbeefdeadbeefdeadbeefdeadbeef'),
    '-0xdeadbeefdeadbeefdeadbeefdeadbeef'
  );

  t.equal(
    t_hex('3735928559373592855937359285593735928559'),
    '0xafa99ab130406c288189c7f3658ef9aef'
  );

  fc.assert(
    fc.property(fc.bigIntN(N), n => {
      t.equal(t_hex(n, 2), BigIntMath.toHex(n));
    })
  );

  t.end();
})

Summary: The `t_hex` function converts numbers or strings into their hexadecimal representation, optionally verifying the conversion against `BigIntMath.toHex` for large integers.


t.test('identities', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), n => {
      // identity ~(~x) = x
      t.equal(to(mpz.not(mpz.not(from(n)))), n);

      t.equal(t_and(n, n), n);
      t.equal(t_or(n, n), n);
      t.equal(t_xor(n, n), 0n);
    })
  );

  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigInt({ min: 1n, max: 4096n }), (n, m) => {
      // a << b >> b = a
      t.equal(to(mpz.shr(mpz.shl(from(n), from(m)), from(m))), n);
    })
  );

  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(N), (x, y) => {
      const X = from(x);
      const Y = from(y);

      t.equal(to(mpz.not(mpz.and(X, Y))), ~x | ~y); // ~(x & y) = ~x | ~y
      t.equal(to(mpz.not(mpz.or(X, Y))), ~x & ~y); // ~(x | y) = ~x & ~y
      // TODO: identity x^y == x|y &~ x&y
    })
  );

  t.end();
})

Summary: Verifies identities for bitwise operations with `mpz` functions: double negation returns the original value, bitwise operations with the same operands return consistent results, shifting left then right returns the original, De Morgan's laws for `and` and `or`, and a placeholder for XOR identity.


t.test('toExponential', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.integer({ min: 0, max: 200 }), (n, m) => {
      t.equal(t_exponential(n, m), BigIntMath.toExponential(n, m));
    }),
    {
      examples: [
        [0, 0],
        [38831928, 8], // causes rounding error if converted to a float
        [-474130365, 7], // causes rounding difference when fp === 0.5
        [474130365, 7], // causes rounding difference when fp === 0.5
        [995163856, 1] // causes carry after rounding
      ]
    }
  );

  t.end();
})

Summary: The property should ensure that the `t_exponential` function accurately replicates the behavior of `BigIntMath.toExponential` for different combinations of big integers and precision levels.


t.test('mul_pow2', t => {
  fc.assert(
    fc.property(
      fc.bigIntN(N),
      fc.bigInt({ min: 0n, max: 2n ** 16n }),
      (n, m) => {
        t.equal(t_mul_pow2(n, m), n * 2n ** m);
      }
    ),
    {
      examples: [
        [-1n, 1n],
        [1n, 1n],
        [0xdeadbeefn, 1n],
        [0xdeadbeefn, 8n],
        [0xdeadbeefn, 32n],
        [0xdeadbeefn, 64n],
        [-0xdeadbeefn, 64n]
      ]
    }
  );

  t.end();
})

Summary: `mul_pow2` should compute the product of a given bigint and two raised to the power of another given bigint, matching the expected mathematical result.


t.test('<<', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(15), (n, m) => {
      t.equal(t_shl(n, m), n << m);
    }),
    {
      examples: [
        [1n, -1n],
        [-1n, 1n],
        [1n, 1n],
        [-1n, -1n],
        [0xdeadbeefn, 1n],
        [0xdeadbeefn, 8n],
        [0xdeadbeefn, 32n],
        [0xdeadbeefn, 64n],
        [-0xdeadbeefn, 64n]
      ]
    }
  );

  t.end();
})

Summary: The property should hold that `t_shl(n, m)` produces the same result as the left shift operator `n << m` for given big integers `n` and `m`.


t.test('xor', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(N), (n, m) => {
      t.equal(t_xor(n, m), n ^ m);
    })
  );

  t.end();
})

Summary: The `t_xor` function should perform the XOR operation identically to the native XOR operation for big integers of bit length N.


Summary: Ensures `t_add` correctly performs addition on pairs of big integers, verifying against the native addition operator.


Summary: `subtraction` verification ensures `t_sub(n, m)` accurately computes subtraction of two big integers, matching `n - m`.


t.test('invariants', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), n => {
      // -(-n) = n
      t.equal(to(mpz.negate(mpz.negate(from(n)))), n);

      // identity
      t.equal(t_add(n, 0n), n);
      t.equal(t_add(0n, n), n);
      t.equal(t_sub(n, 0n), n);
      t.equal(t_sub(0n, n), -n);
    })
  );

  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(N), (n, m) => {
      // (n+m)-m = n
      t.equal(to(mpz.sub(mpz.add(from(n), from(m)), from(m))), n);

      // commutative
      t.equal(t_add(n, m), t_add(m, n));
      t.equal(t_sub(n, m), t_add(n, -m));
    })
  );

  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(N), fc.bigIntN(N), (a, b, c) => {
      const A = from(a);
      const B = from(b);
      const C = from(c);

      // associative
      // (a+b)+c = a+(b+c)
      t.equal(to(mpz.add(mpz.add(A, B), C)), to(mpz.add(A, mpz.add(B, C))));
      // (a-b)-c = a-(b+c)
      t.equal(to(mpz.sub(mpz.sub(A, B), C)), to(mpz.sub(A, mpz.add(B, C))));
      // (a+b)-c = a+(b-c)
      t.equal(to(mpz.sub(mpz.add(A, B), C)), to(mpz.add(A, mpz.sub(B, C))));
    })
  );

  t.end();
})

Summary: Verifies properties of negation, identity, commutativity, and associativity for addition and subtraction of arbitrary large integers.


Summary: The `t_cmp` function should match the behavior of `BigIntMath.cmp` when comparing pairs of big integers.


t.test('multiplication', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(N), (n, m) => {
      t.equal(t_mul(n, m), n * m);
    }),
    {
      examples: [
        // positive
        [0n, 0n],
        [1n, 1n],
        [0x10n, 0x10n],
        [0xdead0000n, 0x0000beefn],
        [0xffffn, 0xffffn],
        [0xffffffffn, 0xffffffffn],
        [
          0x2e75f2aa067132a276c13262e7268d7cecc8190a00000n,
          0x35f29e388c20bfbac4964bfba000n
        ],

        // n<0, m<0
        [-0x10n, -0x10n],
        [-0xffffn, -0xffffn],
        [-0xffffffffn, -0xffffffffn],

        // n>0, m<0
        [0x10n, -0x10n],
        [0xffffn, -0xffffn],
        [0xffffffffn, -0xffffffffn],

        // n<0, m>0
        [-0x10n, 0x10n],
        [-0xffffn, 0xffffn],
        [-0xffffffffn, 0xffffffffn]
      ]
    }
  );

  t.end();
})

Summary: The property should hold that the multiplication function `t_mul` produces the same result as the standard multiplication operation between pairs of big integers.


t.test('division', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(N), (n, m) => {
      m = m || 1n;
      t.equal(t_div(n, m), n / m);
    }),
    {
      examples: [
        // S(m)=1
        [1n, 1n],
        [2n, 1n],
        [4n, 1n],

        // n<m
        [2n, 4n],
        [0xffffffffffffffffn, 0xfffffffffffffffffn],

        // n=m
        [2n, 2n],
        [0xffffffffffffffffn, 0xffffffffffffffffn],

        // 1<m<0xFFFFFFFF, 1<n<0xFFFFFFFF
        [2n, 2n],
        [4n, 2n],
        [8n, 2n],
        [0xbeefn, 16n],
        [0x1000n, 0x10n],
        [0x10000000n, 0x10n],
        [0xdeadbeefn, 16n],
        [0xdeadbeefn, 0x100n],
        [0xdeadbeefn, 0x10000000n],
        [0xffffffffn, 0xfn],
        [0xffffffffn, 0xffffffffn],
        [0xffffffffn, 0xfffffffn],

        // n>0xFFFFFFFF, 1<m<0xFFFFFFFF
        [0xdeadbeefdeadbeefn, 1n],
        [0xdeadbeefdeadbeefn, 0x10n],
        [0xdeadbeefdeadbeefn, 0x100n],
        [0xffffffffffffffffn, 0xfn],
        [0xffffffffffffffffn, 0xffffffffn],
        [0xffffffffffffffffn, 0xfffffffn],

        // n>m>0xFFFFFFFF
        [0xffffffffffffffffn, 0xfffffffffffffffn],
        [0xffffffffffffffffn, 0xfffffffffffffn],
        [0xffffffffffffffffffffn, 0xfffffffffffffffffffn],
        [0xffffffffffffffffffffn, 0xfffffffffffffffffn],
        [0xdeadbeefdeadbeef00000000n, 0xdeadbeefdeadbeef0000n],

        // Special Cases
        [34125305527818743474129076526n, 9580783237862390338n], // requires two D3 correction steps
        [0x100229888f0870594265f617feeb3bb879c7d35ecd04fn, 2n ** 89n - 1n], // Requires D6 correction step
        [
          0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
          2n ** 521n - 1n
        ]
      ]
    }
  );

  t.end();
})

Summary: The test ensures that dividing two big integers using `t_div` produces the same result as using the native division operator, across a range of examples and random inputs, with specific handling for zero denominators.


t.test('mul-div invariants', t => {
  fc.assert(
    fc.property(fc.bigIntN(N), fc.bigIntN(N), (a, b) => {
      const n = mpz.from(a);
      const d = mpz.from(b || 1n);

      const q = mpz.div(n, d);
      const m = mpz.rem(n, d);
      const r = mpz.add(mpz.mul(q, d), m);
      t.equal(mpz.toHex(r), mpz.toHex(n));

      // commutative
      t.equal(t_mul(a, b), t_mul(b, a));
    })
  );

  // distributive
  // a*(b+c) = a*b + a*c

  fc.assert(
    fc.property(fc.bigIntN(N), n => {
      // identity
      t.equal(t_mul(n, 1n), n);
      t.equal(t_div(n, 1n), n);

      // inverse
      if (n !== 0n) {
        t.equal(t_div(n, n), 1n);
      }
    })
  );

  t.end();
})

Summary: The properties being tested include the invariant that, given two big integers `a` and `b`, dividing `a` by `b`, multiplying the quotient by `b`, and adding the remainder should reconstruct `a`; multiplication is commutative; multiplication by one is an identity operation; division by one is an identity operation; and division by a number itself results in one, provided the number is not zero.