-
Notifications
You must be signed in to change notification settings - Fork 185
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Use property based testing; Adjust the types; Add serializatio…
…n and all schemas
- Loading branch information
1 parent
9f0477c
commit de833f4
Showing
9 changed files
with
298 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,43 @@ | ||
import { OmnichainGraphCoordinate } from "./types" | ||
import { OmnichainEdgeCoordinates, OmnichainNodeCoordinate } from "./types" | ||
|
||
export const areSameCoordinates = (a: OmnichainGraphCoordinate, b: OmnichainGraphCoordinate): boolean => | ||
a.address === b.address && a.eid === b.eid | ||
/** | ||
* Compares two coordinates by value | ||
* | ||
* @param a `OmnichainNodeCoordinate` | ||
* @param b `OmnichainNodeCoordinate` | ||
* | ||
* @returns `true` if the coordinates point to the same point in omniverse | ||
*/ | ||
export const isCoordinateEqual = (a: OmnichainNodeCoordinate, b: OmnichainNodeCoordinate): boolean => a.address === b.address && a.eid === b.eid | ||
|
||
export const serializeCoordinate = ({ address, eid }: OmnichainGraphCoordinate): string => `${eid}|${address}` | ||
/** | ||
* Compares two coordinate vectors | ||
* | ||
* @param a `OmnichainEdgeCoordinates` | ||
* @param b `OmnichainEdgeCoordinates` | ||
* | ||
* @returns `true` if the coordinates point from and to the same point in omniverse | ||
*/ | ||
export const areCoordinatesEqual = (a: OmnichainEdgeCoordinates, b: OmnichainEdgeCoordinates): boolean => | ||
isCoordinateEqual(a.from, b.from) && isCoordinateEqual(a.to, b.to) | ||
|
||
/** | ||
* Serializes a coordinate. Useful for when coordinates need to be used in Map | ||
* where we cannot adjust the default behavior of using a reference equality | ||
* | ||
* @param coordinate `OmnichainNodeCoordinate` | ||
* | ||
* @returns `string` | ||
*/ | ||
export const serializeCoordinate = ({ address, eid }: OmnichainNodeCoordinate): string => `${eid}|${address}` | ||
|
||
/** | ||
* Serializes coordinate vector. Useful for when coordinates need to be used in Map | ||
* where we cannot adjust the default behavior of using a reference equality | ||
* | ||
* @param coordinate `OmnichainEdgeCoordinates` | ||
* | ||
* @returns `string` | ||
*/ | ||
export const serializeCoordinates = ({ from, to }: OmnichainEdgeCoordinates): string => | ||
`${serializeCoordinate(from)} → ${serializeCoordinate(to)}` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,47 @@ | ||
import { EndpointId } from "@layerzerolabs/lz-definitions" | ||
import { z } from "zod" | ||
import type { OmnichainGraphCoordinate, OmnichainGraphNode } from "./types" | ||
import type { OmnichainNodeCoordinate, OmnichainNode, OmnichainEdgeCoordinates, OmnichainEdge } from "./types" | ||
|
||
export const AddressSchema = z.string() | ||
|
||
export const EndpointIdSchema = z.nativeEnum(EndpointId).pipe(z.number()) | ||
export const EndpointIdSchema: z.ZodSchema<EndpointId, z.ZodTypeDef, unknown> = z.nativeEnum(EndpointId).pipe(z.number()) | ||
|
||
export const OmnichainGraphCoordinateSchema: z.ZodSchema<OmnichainGraphCoordinate, z.ZodTypeDef, unknown> = z.object({ | ||
export const OmnichainNodeCoordinateSchema: z.ZodSchema<OmnichainNodeCoordinate, z.ZodTypeDef, unknown> = z.object({ | ||
address: AddressSchema, | ||
eid: EndpointIdSchema, | ||
}) | ||
|
||
export const createOmnichainGraphNodeSchema = <TConfig = unknown>( | ||
export const OmnichainEdgeCoordinatesSchema: z.ZodSchema<OmnichainEdgeCoordinates, z.ZodTypeDef, unknown> = z.object({ | ||
from: OmnichainNodeCoordinateSchema, | ||
to: OmnichainNodeCoordinateSchema, | ||
}) | ||
|
||
/** | ||
* Factory for OmnichainNode schemas | ||
* | ||
* @param configSchema Schema of the config contained in the node | ||
* | ||
* @returns `z.ZodSchema<OmnichainNode<TConfig>>` schema for a node with the particular config type | ||
*/ | ||
export const createOmnichainNodeSchema = <TConfig = unknown>( | ||
configSchema: z.ZodSchema<TConfig, z.ZodTypeDef, unknown> | ||
): z.ZodSchema<OmnichainNode<TConfig>, z.ZodTypeDef, unknown> => | ||
z.object({ | ||
coordinate: OmnichainNodeCoordinateSchema, | ||
config: configSchema, | ||
}) as z.ZodSchema<OmnichainNode<TConfig>, z.ZodTypeDef, unknown> | ||
|
||
/** | ||
* Factory for OmnichainEdge schemas | ||
* | ||
* @param configSchema `z.ZodSchema<TConfig>` Schema of the config contained in the edge | ||
* | ||
* @returns `z.ZodSchema<OmnichainEdge<TConfig>>` schema for an edge with the particular config type | ||
*/ | ||
export const createOmnichainEdgeSchema = <TConfig = unknown>( | ||
configSchema: z.ZodSchema<TConfig, z.ZodTypeDef, unknown> | ||
): z.ZodSchema<OmnichainGraphNode<TConfig>, z.ZodTypeDef, unknown> => | ||
): z.ZodSchema<OmnichainEdge<TConfig>, z.ZodTypeDef, unknown> => | ||
z.object({ | ||
coordinate: OmnichainGraphCoordinateSchema, | ||
coordinates: OmnichainEdgeCoordinatesSchema, | ||
config: configSchema, | ||
}) as z.ZodSchema<OmnichainGraphNode<TConfig>, z.ZodTypeDef, unknown> | ||
}) as z.ZodSchema<OmnichainEdge<TConfig>, z.ZodTypeDef, unknown> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import fc from "fast-check" | ||
import { EndpointId } from "@layerzerolabs/lz-definitions" | ||
import { ENDPOINT_IDS } from "./constants" | ||
import { OmnichainNodeCoordinate, OmnichainEdgeCoordinates } from "@/types" | ||
|
||
export const addressArbitrary = fc.string() | ||
|
||
export const endpointArbitrary: fc.Arbitrary<EndpointId> = fc.constantFrom(...ENDPOINT_IDS) | ||
|
||
export const coordinateArbitrary: fc.Arbitrary<OmnichainNodeCoordinate> = fc.record({ | ||
eid: endpointArbitrary, | ||
address: addressArbitrary, | ||
}) | ||
|
||
export const coordinatesArbitrary: fc.Arbitrary<OmnichainEdgeCoordinates> = fc.record({ | ||
from: coordinateArbitrary, | ||
to: coordinateArbitrary, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { EndpointId } from "@layerzerolabs/lz-definitions" | ||
import { EndpointIdSchema } from "../../src/schema" | ||
|
||
export const ENDPOINT_IDS = Object.values(EndpointId).filter((value): value is EndpointId => EndpointIdSchema.safeParse(value).success) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,125 @@ | ||
import { areSameCoordinates } from "@/coordinates" | ||
import { OmnichainGraphCoordinate } from "@/types" | ||
import { EndpointId } from "@layerzerolabs/lz-definitions" | ||
import fc from "fast-check" | ||
import { areCoordinatesEqual, isCoordinateEqual, serializeCoordinate, serializeCoordinates } from "@/coordinates" | ||
import { coordinateArbitrary, addressArbitrary, endpointArbitrary, coordinatesArbitrary } from "./__utils__/arbitraries" | ||
|
||
describe("coordinates", () => { | ||
describe("areSameCoordinates", () => { | ||
type TestCase = [OmnichainGraphCoordinate, OmnichainGraphCoordinate] | ||
|
||
const GOOD: TestCase[] = [ | ||
[ | ||
{ eid: EndpointId.BSC_TESTNET, address: "0x0" }, | ||
{ eid: EndpointId.BSC_TESTNET, address: "0x0" }, | ||
], | ||
[ | ||
{ eid: EndpointId.SOLANA_MAINNET, address: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" }, | ||
{ eid: EndpointId.SOLANA_MAINNET, address: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So" }, | ||
], | ||
] | ||
|
||
it.each(GOOD)(`should be true for %j and %j`, (a, b) => { | ||
expect(areSameCoordinates(a, b)).toBeTruthy() | ||
expect(areSameCoordinates(a, a)).toBeTruthy() | ||
expect(areSameCoordinates(b, b)).toBeTruthy() | ||
describe("assertions", () => { | ||
describe("isCoordinateEqual", () => { | ||
it("should be true for referentially equal coordinates", () => { | ||
fc.assert( | ||
fc.property(coordinateArbitrary, (coordinate) => { | ||
expect(isCoordinateEqual(coordinate, coordinate)).toBeTruthy() | ||
}) | ||
) | ||
}) | ||
|
||
it("should be true for value equal coordinates", () => { | ||
fc.assert( | ||
fc.property(coordinateArbitrary, (coordinate) => { | ||
expect(isCoordinateEqual(coordinate, { ...coordinate })).toBeTruthy() | ||
}) | ||
) | ||
}) | ||
|
||
it("should be false when addresses don't match", () => { | ||
fc.assert( | ||
fc.property(coordinateArbitrary, addressArbitrary, (coordinate, address) => { | ||
fc.pre(coordinate.address !== address) | ||
|
||
expect(isCoordinateEqual(coordinate, { ...coordinate, address })).toBeFalsy() | ||
}) | ||
) | ||
}) | ||
|
||
it("should be false when endpoint IDs don't match", () => { | ||
fc.assert( | ||
fc.property(coordinateArbitrary, endpointArbitrary, (coordinate, eid) => { | ||
fc.pre(coordinate.eid !== eid) | ||
|
||
expect(isCoordinateEqual(coordinate, { ...coordinate, eid })).toBeFalsy() | ||
}) | ||
) | ||
}) | ||
}) | ||
|
||
const BAD: TestCase[] = [ | ||
[ | ||
{ eid: EndpointId.ETHEREUM_MAINNET, address: "0x0" }, | ||
{ eid: EndpointId.BSC_TESTNET, address: "0x0" }, | ||
], | ||
[ | ||
{ eid: EndpointId.ETHEREUM_MAINNET, address: "0x0" }, | ||
{ eid: EndpointId.ETHEREUM_MAINNET, address: "0x1" }, | ||
], | ||
[ | ||
{ eid: EndpointId.ETHEREUM_MAINNET, address: "0xa" }, | ||
{ eid: EndpointId.ETHEREUM_MAINNET, address: "0xA" }, | ||
], | ||
] | ||
|
||
it.each(BAD)(`should be false for %j and %j`, (a, b) => { | ||
expect(areSameCoordinates(a, b)).toBeFalsy() | ||
describe("areCoordinatesEqual", () => { | ||
it("should be true for referentially equal coordinates", () => { | ||
fc.assert( | ||
fc.property(coordinatesArbitrary, (coordinates) => { | ||
expect(areCoordinatesEqual(coordinates, coordinates)).toBeTruthy() | ||
}) | ||
) | ||
}) | ||
|
||
it("should be true for value equal coordinates", () => { | ||
fc.assert( | ||
fc.property(coordinatesArbitrary, (coordinates) => { | ||
expect(areCoordinatesEqual(coordinates, { ...coordinates })).toBeTruthy() | ||
}) | ||
) | ||
}) | ||
|
||
it("should be false when from coordinate doesn't match", () => { | ||
fc.assert( | ||
fc.property(coordinatesArbitrary, coordinateArbitrary, (coordinates, from) => { | ||
fc.pre(!isCoordinateEqual(coordinates.from, from)) | ||
|
||
expect(areCoordinatesEqual(coordinates, { ...coordinates, from })).toBeFalsy() | ||
}) | ||
) | ||
}) | ||
|
||
it("should be false when to coordinate doesn't match", () => { | ||
fc.assert( | ||
fc.property(coordinatesArbitrary, coordinateArbitrary, (coordinates, to) => { | ||
fc.pre(!isCoordinateEqual(coordinates.from, to)) | ||
|
||
expect(areCoordinatesEqual(coordinates, { ...coordinates, to })).toBeFalsy() | ||
}) | ||
) | ||
}) | ||
}) | ||
}) | ||
|
||
describe("serialization", () => { | ||
describe("serializeCoordinate", () => { | ||
it("should produce identical serialized values if the coordinates match", () => { | ||
fc.assert( | ||
fc.property(coordinateArbitrary, (coordinate) => { | ||
expect(serializeCoordinate(coordinate)).toBe(serializeCoordinate({ ...coordinate })) | ||
}) | ||
) | ||
}) | ||
|
||
it("should produce different serialized values if the coordinates don't match", () => { | ||
fc.assert( | ||
fc.property(coordinateArbitrary, coordinateArbitrary, (coordinateA, coordinateB) => { | ||
fc.pre(!isCoordinateEqual(coordinateA, coordinateB)) | ||
|
||
expect(serializeCoordinate(coordinateA)).not.toBe(serializeCoordinate(coordinateB)) | ||
}) | ||
) | ||
}) | ||
}) | ||
|
||
describe("serializeCoordinates", () => { | ||
it("should produce identical serialized values if the coordinates match", () => { | ||
fc.assert( | ||
fc.property(coordinatesArbitrary, (coordinates) => { | ||
expect(serializeCoordinates(coordinates)).toBe(serializeCoordinates({ ...coordinates })) | ||
}) | ||
) | ||
}) | ||
|
||
it("should produce different serialized values if the coordinates don't match", () => { | ||
fc.assert( | ||
fc.property(coordinatesArbitrary, coordinatesArbitrary, (coordinatesA, coordinatesB) => { | ||
fc.pre(!areCoordinatesEqual(coordinatesA, coordinatesB)) | ||
|
||
expect(serializeCoordinates(coordinatesA)).not.toBe(serializeCoordinates(coordinatesB)) | ||
}) | ||
) | ||
}) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.