import { describe, expect, test } from "bun:test"; import { Parse, ParseError } from "../index.ts"; describe(Parse.unknown, () => { test("returns the value as provided", () => { const val = Parse.unknown("hello"); expect(val).toBe("hello"); }); }); describe(Parse.string, () => { test("Parses strings", () => { expect(Parse.string("hello")).toBe("hello"); }); test("Throws an error when parsing a non-string", () => { const INVALID_VALUES = [null, undefined, 123, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.string(val)).toThrow(ParseError); } }); }); describe(Parse.number, () => { test("Parses numbers", () => { expect(Parse.number(123)).toBe(123); }); test("Throws an error when parsing a non-number", () => { const INVALID_VALUES = [null, undefined, "hello", true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.number(val)).toThrow(ParseError); } }); }); describe(Parse.boolean, () => { test("Parses booleans", () => { expect(Parse.boolean(true)).toBe(true); expect(Parse.boolean(false)).toBe(false); }); test("Throws an error when parsing a non-boolean", () => { const INVALID_VALUES = [null, undefined, "hello", 123, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.boolean(val)).toThrow(ParseError); } }); }); describe(Parse.bigint, () => { test("Parses bigints", () => { expect(Parse.bigint(BigInt(123))).toBe(BigInt(123)); }); test("Throws an error when parsing a non-bigint", () => { const INVALID_VALUES = [null, undefined, "hello", 123, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.bigint(val)).toThrow(ParseError); } }); }); describe(Parse.symbol, () => { test("Parses symbols", () => { const symbol = Symbol("hello"); expect(Parse.symbol(symbol)).toBe(symbol); }); test("Throws an error when parsing a non-symbol", () => { const INVALID_VALUES = [null, undefined, "hello", 123, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.symbol(val)).toThrow(ParseError); } }); }); describe(Parse.null, () => { test("Parses null", () => { expect(Parse.null(null)).toBe(null); }); test("Throws an error when parsing a non-null", () => { const INVALID_VALUES = [undefined, "hello", 123, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.null(val)).toThrow(ParseError); } }); }); describe(Parse.undefined, () => { test("Parses undefined", () => { expect(Parse.undefined(undefined)).toBe(undefined); }); test("Throws an error when parsing a non-undefined", () => { const INVALID_VALUES = [null, "hello", 123, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.undefined(val)).toThrow(ParseError); } }); }); describe(Parse.arrayOf, () => { test("Parses arrays of a specific type", () => { const arr = [1, 2, 3]; expect(Parse.arrayOf(Parse.number)(arr)).toEqual(arr); }); test("Throws an error when parsing a non-array", () => { expect(() => Parse.arrayOf(Parse.number)("hello")).toThrow(ParseError); }); test("Throws an error when parsing an array with invalid values", () => { const INVALID_VALUES = [null, undefined, "hello", true, false, {}]; for (const val of INVALID_VALUES) { const arr = [1, val, 3]; expect(() => Parse.arrayOf(Parse.number)(arr)).toThrow(ParseError); } }); }); describe(Parse.shape, () => { test("Parses objects", () => { const obj = { name: "hello", age: 123 }; const shape = { name: Parse.string, age: Parse.number }; expect(Parse.shape(shape)(obj)).toEqual(obj); }); test("Throws an error when parsing a non-object", () => { expect(() => Parse.shape({})("hello")).toThrow(ParseError); }); test("Throws an error when parsing an object with invalid values", () => { const obj = { name: "hello", age: "world" }; const shape = { name: Parse.string, age: Parse.number }; expect(() => Parse.shape(shape)(obj)).toThrow(ParseError); }); test("allows optional object entries", () => { const parseThing = Parse.shape({ name: Parse.string, another: Parse.optional(Parse.string), }); const result = parseThing({ name: "hello", }); expect(result).toEqual({ name: "hello", another: undefined, }); }); test("allows nullable entries", () => { const parseThing = Parse.shape({ name: Parse.string, another: Parse.nullable(Parse.string), }); expect(parseThing({ name: "hello", another: null })).toEqual({ name: "hello", another: null, }); }); test("nullable entries can accpet undefined when configured as such", () => { const parseThing = Parse.shape({ name: Parse.string, another: Parse.nullable(Parse.string, true), }); const obj = { name: "hello", another: undefined, }; const result = parseThing(obj); expect(result).toEqual({ name: "hello", another: null, }); }); test("optional entries can accpet null when configured as such", () => { const parseThing = Parse.shape({ name: Parse.string, another: Parse.optional(Parse.string, true), }); const obj = { name: "hello", another: null, }; const result = parseThing(obj); expect(result).toEqual({ name: "hello", another: undefined, }); }); test("throws when a required value is missing", () => { const parseThing = Parse.shape({ name: Parse.string, another: Parse.optional(Parse.string), }); expect(() => { parseThing({ another: "hello" }); }).toThrow(ParseError); }); }); describe(Parse.enum, () => { test("Parses valid enum values", () => { const enumValues = ["hello", "world"] as const; expect(Parse.enum(enumValues)("hello")).toBe("hello"); }); test("Throws an error when parsing an invalid enum value", () => { const enumValues = ["hello", "world"] as const; expect(() => Parse.enum(enumValues)("invalid")).toThrow(ParseError); }); }); describe(Parse.regex, () => { test("Parses valid regex values", () => { expect(Parse.regex(/hello/)("hello")).toBe("hello"); }); test("Throws an error when parsing an invalid regex value", () => { expect(() => Parse.regex(/hello/)("world")).toThrow(ParseError); }); }); describe(Parse.optional, () => { test("Parses undefined values", () => { expect(Parse.optional(Parse.string)(undefined)).toBeUndefined(); }); test("Parses null values when configured", () => { expect(Parse.optional(Parse.string, true)(null)).toBeUndefined(); }); }); describe(Parse.nullable, () => { test("Parses null values", () => { expect(Parse.nullable(Parse.string)(null)).toBeNull(); }); test("Parses undefined values when configured", () => { expect(Parse.nullable(Parse.string, true)(undefined)).toBeNull(); }); }); describe(Parse.defaulted, () => { test("Parses uses a default value for undefined params", () => { expect(Parse.defaulted(Parse.string, "default!")(undefined)).toBe( "default!", ); }); }); describe(Parse.nan, () => { test("Parses NaN", () => { expect(Parse.nan(Number.NaN)).toBe(Number.NaN); }); test("Throws an error when parsing a non-NaN", () => { const INVALID_VALUES = [null, undefined, "hello", 123, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.nan(val)).toThrow(ParseError); } }); }); class TestClass { } describe(Parse.instanceOf, () => { test("Parses instances of a class", () => { const testClass = new TestClass(); expect(Parse.instanceOf(TestClass)(testClass)).toBe(testClass); }); test("Throws an error when parsing a non-instance", () => { const INVALID_VALUES = [null, undefined, "hello", 123, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.instanceOf(TestClass)(val)).toThrow(ParseError); } }); test("Throws an error when parsing an instance of a different class", () => { const testClass = new TestClass(); expect(() => Parse.instanceOf(class AnotherClass { })(testClass)).toThrow( ParseError, ); }); }); describe(Parse.oneOf, () => { test("Parses values that match one of the parsers", () => { const parsers = [Parse.string, Parse.number]; expect(Parse.oneOf(parsers)("hello")).toEqual("hello"); }); test("Throws an error when parsing a value that doesn't match any parser", () => { const parsers = [Parse.string, Parse.number]; const INVALID_VALUES = [null, undefined, true, false, {}]; for (const val of INVALID_VALUES) { expect(() => Parse.oneOf(parsers)(val)).toThrow(ParseError); } }); }); describe(Parse.recordOf, () => { test("Parses records of a specific type", () => { const stringToString = Parse.recordOf(Parse.string, Parse.string); const rec = { key: "value", another: "another", }; const badRec = { key: "value", another: 1, }; expect(stringToString(rec)).toEqual(rec); expect(() => stringToString(badRec)).toThrow(ParseError); }); });