import { Parser } from "ts-matches"; import { UnionSelectKey, unionSelectKey, UnionValueKey, unionValueKey, } from "../config/configTypes"; import { InputSpec, matchInputSpec, testListUnion } from "./output"; export type IfEquals = (() => G extends T ? 1 : 2) extends () => G extends U ? 1 : 2 ? Y : N; export function testOutput(): (c: IfEquals) => null { return () => null; } function isObject(item: unknown): item is object { return !!(item && typeof item === "object" && !Array.isArray(item)); } type UnionToIntersection = (T extends any ? (x: T) => any : never) extends ( x: infer R ) => any ? R : never; export function mergeDeep(...sources: A) { return _mergeDeep({}, ...sources); } function _mergeDeep( target: UnionToIntersection | {}, ...sources: A ): UnionToIntersection | {} { if (!sources.length) return target; const source = sources.shift(); if (isObject(target) && isObject(source)) { for (const key in source) { if (isObject((source as any)[key])) { if (!(target as any)[key]) Object.assign(target, { [key]: {} }); _mergeDeep((target as any)[key], (source as any)[key]); } else { Object.assign(target, { [key]: (source as any)[key] }); } } } return _mergeDeep(target, ...sources); } /// Testing the types of the input spec // @ts-expect-error Because enable should be a boolean testOutput()(null); testOutput()(null); testOutput()(null); testOutput()(null); testOutput< InputSpec["rpc"]["advanced"]["serialversion"], "segwit" | "non-segwit" >()(null); testOutput()(null); testOutput()( null ); testOutput< InputSpec["testListUnion"][0]["union"][UnionValueKey]["name"], string >()(null); testOutput()( null ); // prettier-ignore // @ts-expect-error Expect that the string is the one above testOutput()(null); /// Here we test the output of the matchInputSpec function describe("Inputs", () => { const validInput: InputSpec = { testListUnion: [ { union: { [unionSelectKey]: "lnd", [unionValueKey]: { name: "string" } }, }, ], rpc: { enable: true, bio: "This is a bio", username: "test", password: "test", advanced: { auth: ["test"], serialversion: "segwit", servertimeout: 6, threads: 3, workqueue: 9, }, }, "zmq-enabled": false, txindex: false, wallet: { enable: false, avoidpartialspends: false, discardfee: 0.0001 }, advanced: { mempool: { maxmempool: 1, persistmempool: true, mempoolexpiry: 23, mempoolfullrbf: true, }, peers: { listen: true, onlyconnect: true, onlyonion: true, addnode: [ { hostname: "test", port: 1, }, ], }, dbcache: 5, pruning: { unionSelectKey: "disabled", unionValueKey: {}, }, blockfilters: { blockfilterindex: false, peerblockfilters: false, }, bloomfilters: { peerbloomfilters: false }, }, }; test("Test just the input unions", () => { testListUnion.validator().unsafeCast(validInput.testListUnion); }); test("test valid input", () => { const output = matchInputSpec.unsafeCast(validInput); expect(output).toEqual(validInput); }); test("test errors", () => { expect(() => matchInputSpec.unsafeCast( mergeDeep(validInput, { rpc: { advanced: { threads: 0 } } }) ) ).toThrowError(); expect(() => matchInputSpec.unsafeCast(mergeDeep(validInput, { rpc: { enable: 2 } })) ).toThrowError(); expect(() => matchInputSpec.unsafeCast( mergeDeep(validInput, { rpc: { advanced: { serialversion: "testing" } }, }) ) ).toThrowError(); }); });