From 870f232689b8a6c7e147a41ac5d93cac1d999000 Mon Sep 17 00:00:00 2001 From: Yamiteru Date: Thu, 2 May 2024 21:59:34 +0200 Subject: [PATCH] feat: add tests --- package.json | 7 +++-- tests/array.test.ts | 32 ++++++++++++++++++++++ tests/assert.test.ts | 34 ++++++++++++++++++++++++ tests/boolean.test.ts | 14 ++++++++++ tests/enum.test.ts | 15 +++++++++++ tests/float.test.ts | 23 ++++++++++++++++ tests/int.test.ts | 60 ++++++++++++++++++++++++++++++++++++++++++ tests/nullable.test.ts | 24 +++++++++++++++++ tests/object.test.ts | 22 ++++++++++++++++ tests/shared.ts | 7 +++++ tests/string.test.ts | 28 ++++++++++++++++++++ tests/tuple.test.ts | 19 +++++++++++++ tsconfig.json | 2 +- 13 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 tests/array.test.ts create mode 100644 tests/assert.test.ts create mode 100644 tests/boolean.test.ts create mode 100644 tests/enum.test.ts create mode 100644 tests/float.test.ts create mode 100644 tests/int.test.ts create mode 100644 tests/nullable.test.ts create mode 100644 tests/object.test.ts create mode 100644 tests/shared.ts create mode 100644 tests/string.test.ts create mode 100644 tests/tuple.test.ts diff --git a/package.json b/package.json index caa496a..5ca061d 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,15 @@ "scripts": { "start": "bun index.ts", "check": "bunx @biomejs/biome check --apply ./", - "build": "tsup" + "build": "tsup", + "test": "vitest" }, "devDependencies": { "@biomejs/biome": "1.7.0", + "@fast-check/vitest": "0.1.1", "@types/bun": "latest", - "tsup": "8.0.2" + "tsup": "8.0.2", + "vitest": "1.5.3" }, "peerDependencies": { "typescript": "5.4.5" diff --git a/tests/array.test.ts b/tests/array.test.ts new file mode 100644 index 0000000..fbf2e74 --- /dev/null +++ b/tests/array.test.ts @@ -0,0 +1,32 @@ +import {fc, test} from "@fast-check/vitest"; +import {describe, expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; +import {UINT16, UINT8} from "./shared"; + +describe("array", () => { + test.prop([fc.array(fc.integer(UINT8), { maxLength: UINT8.max })])("8", (value) => { + const type = { + type: "array", + size: 8, + item: {type: "int", size: 8} + } satisfies Protocol.Array; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toEqual(value); + }); + + test.prop([fc.array(fc.integer(UINT8), { maxLength: UINT16.max })])("8", (value) => { + const type = { + type: "array", + size: 16, + item: {type: "int", size: 8} + } satisfies Protocol.Array; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toEqual(value); + }); +}); \ No newline at end of file diff --git a/tests/assert.test.ts b/tests/assert.test.ts new file mode 100644 index 0000000..d5facd1 --- /dev/null +++ b/tests/assert.test.ts @@ -0,0 +1,34 @@ +import {fc, test} from "@fast-check/vitest"; +import {describe, expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; +import {UINT8} from "./shared"; + +describe("assert", () => { + const assert = (value: unknown) => { + if (value === 0) { + throw new Error("zero"); + } + + return value; + }; + + test.prop([fc.integer({ min: 1, max: UINT8.max})])("passes", (value) => { + const type = { type: "int", size: 8, assert } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.constant(0)])("throws", (value) => { + const throwType = { type: "int", size: 8, assert } satisfies Protocol.Int; + const passType = { type: "int", size: 8 } satisfies Protocol.Int; + + expect(() => encode(throwType, value)).toThrow("zero"); + + const encoded = encode(passType, value); + + expect(() => decode(throwType, encoded)).toThrow("zero"); + }); +}); \ No newline at end of file diff --git a/tests/boolean.test.ts b/tests/boolean.test.ts new file mode 100644 index 0000000..f30b47d --- /dev/null +++ b/tests/boolean.test.ts @@ -0,0 +1,14 @@ +import {fc, test} from "@fast-check/vitest"; +import {expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; + +test.prop([fc.boolean()])("boolean", (value) => { + const type = { + type: "boolean", + } satisfies Protocol.Boolean; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toEqual(value); +}); diff --git a/tests/enum.test.ts b/tests/enum.test.ts new file mode 100644 index 0000000..1ad0544 --- /dev/null +++ b/tests/enum.test.ts @@ -0,0 +1,15 @@ +import {fc, test} from "@fast-check/vitest"; +import {expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; + +test.prop([fc.oneof(fc.constant("ADMIN"), fc.constant("USER"))])("enum", (value) => { + const type = { + type: "enum", + options: ["ADMIN", "USER"] + } satisfies Protocol.Enum; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toEqual(value); +}); diff --git a/tests/float.test.ts b/tests/float.test.ts new file mode 100644 index 0000000..f680580 --- /dev/null +++ b/tests/float.test.ts @@ -0,0 +1,23 @@ +import {fc, test} from "@fast-check/vitest"; +import {describe, expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; + +describe("float", () => { + test.prop([fc.float()])("float32", (value) => { + const type = { type: "float", size: 32 } satisfies Protocol.Float; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.integer()])("float64", (value) => { + const type = { type: "float", size: 64 } satisfies Protocol.Float; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); +}); \ No newline at end of file diff --git a/tests/int.test.ts b/tests/int.test.ts new file mode 100644 index 0000000..edfe3a0 --- /dev/null +++ b/tests/int.test.ts @@ -0,0 +1,60 @@ +import {fc, test} from "@fast-check/vitest"; +import {describe, expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; +import {INT16, INT32, INT8, UINT16, UINT32, UINT8} from "./shared"; + +describe("int", () => { + test.prop([fc.integer(UINT8)])("uint8", (value) => { + const type = { type: "int", size: 8, signed: false } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.integer(UINT16)])("uint16", (value) => { + const type = { type: "int", size: 16, signed: false } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.integer(UINT32)])("uint32", (value) => { + const type = { type: "int", size: 32, signed: false } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.integer(INT8)])("int8", (value) => { + const type = { type: "int", size: 8, signed: true } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.integer(INT16)])("int16", (value) => { + const type = { type: "int", size: 16, signed: true } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.integer(INT32)])("int32", (value) => { + const type = { type: "int", size: 32, signed: true } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); +}); \ No newline at end of file diff --git a/tests/nullable.test.ts b/tests/nullable.test.ts new file mode 100644 index 0000000..403e036 --- /dev/null +++ b/tests/nullable.test.ts @@ -0,0 +1,24 @@ +import {fc, test} from "@fast-check/vitest"; +import {describe, expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; +import {UINT8} from "./shared"; + +describe("nullable", () => { + test.prop([fc.oneof(fc.integer(UINT8), fc.constant(null))])("true", (value) => { + const type = { type: "int", size: 8, nullable: true } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.integer(UINT8)])("false", (value) => { + const type = { type: "int", size: 8, nullable: false } satisfies Protocol.Int; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); +}); \ No newline at end of file diff --git a/tests/object.test.ts b/tests/object.test.ts new file mode 100644 index 0000000..4c06c52 --- /dev/null +++ b/tests/object.test.ts @@ -0,0 +1,22 @@ +import {fc, test} from "@fast-check/vitest"; +import {expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; +import {UINT8} from "./shared"; + +test.prop([fc.record({ + name: fc.string(), + age: fc.integer({min: 0, max: 150}), +})])("object", (value) => { + const type = { + type: "object", + properties: [ + {key: "name", type: "string", kind: "ascii", size: 8}, + {key: "age", type: "int", size: 8}, + ] + } satisfies Protocol.Object; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toEqual(value); +}); diff --git a/tests/shared.ts b/tests/shared.ts new file mode 100644 index 0000000..f41fe05 --- /dev/null +++ b/tests/shared.ts @@ -0,0 +1,7 @@ +export const UINT8 = { min: 0, max: 255 }; +export const UINT16 = { min: 0, max: 65_535 }; +export const UINT32 = { min: 0, max: 4_294_967_295 }; + +export const INT8 = {min: -128, max: 127}; +export const INT16 = {min: -32_768, max: 32_767}; +export const INT32 = {min: -2_147_483_648, max: 2_147_483_647}; \ No newline at end of file diff --git a/tests/string.test.ts b/tests/string.test.ts new file mode 100644 index 0000000..c08163a --- /dev/null +++ b/tests/string.test.ts @@ -0,0 +1,28 @@ +import {fc, test} from "@fast-check/vitest"; +import {describe, expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; +import {UINT16, UINT8} from "./shared"; + +describe("string", () => { + describe("ascii", () => { + test.prop([fc.string({ maxLength: UINT8.max })])("8", (value) => { + const type = { type: "string", kind: "ascii", size: 8 } satisfies Protocol.String; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + + test.prop([fc.string({ maxLength: UINT16.max })])("16", (value) => { + const type = { type: "string", kind: "ascii", size: 16 } satisfies Protocol.String; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toBe(value); + }); + }); + + // TODO: once utf8/16 are implemented, add tests for them +}); \ No newline at end of file diff --git a/tests/tuple.test.ts b/tests/tuple.test.ts new file mode 100644 index 0000000..27cc966 --- /dev/null +++ b/tests/tuple.test.ts @@ -0,0 +1,19 @@ +import {fc, test} from "@fast-check/vitest"; +import {expect} from "vitest"; +import {decode, encode, Protocol} from "../src"; +import {UINT8} from "./shared"; + +test.prop([fc.tuple(fc.integer(UINT8), fc.string())])("tuple", (value) => { + const type = { + type: "tuple", + items: [ + {type: "int", size: 8}, + {type: "string", kind: "ascii", size: 8}, + ] + } satisfies Protocol.Tuple; + + const encoded = encode(type, value); + const decoded = decode(type, encoded); + + expect(decoded).toEqual(value); +}); diff --git a/tsconfig.json b/tsconfig.json index c012f64..2edc1a5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,6 +19,6 @@ ] } }, - "include": ["src", "index.ts"], + "include": ["src", "tests","index.ts"], "exclude": ["node_modules"] }