From f368638f6e55e39b743f318f40db4b29551074f0 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Sun, 23 Mar 2025 21:50:49 +0800 Subject: [PATCH] add some test files --- bun.lock | 3 + package.json | 1 + server/common.ts | 18 ++- server/database.test.ts | 31 ++++- server/database.ts | 246 ++++++++++++++++++++++++++-------------- 5 files changed, 212 insertions(+), 87 deletions(-) diff --git a/bun.lock b/bun.lock index ebe77b3..ba78f2b 100644 --- a/bun.lock +++ b/bun.lock @@ -7,6 +7,7 @@ "@trpc/client": "^10.45.2", "@trpc/server": "^10.45.2", "@types/lodash": "^4.17.16", + "lodash": "^4.17.21", "log-symbols": "^7.0.0", "pinia": "^3.0.1", "trpc-bun-adapter": "^1.2.2", @@ -434,6 +435,8 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="], + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "log-symbols": ["log-symbols@7.0.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-zrc91EDk2M+2AXo/9BTvK91pqb7qrPg2nX/Hy+u8a5qQlbaOflCKO+6SqgZ+M+xUFxGdKTgwnGiL96b1W3ikRA=="], "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], diff --git a/package.json b/package.json index d1fa9c7..66deb12 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@trpc/client": "^10.45.2", "@trpc/server": "^10.45.2", "@types/lodash": "^4.17.16", + "lodash": "^4.17.21", "log-symbols": "^7.0.0", "pinia": "^3.0.1", "trpc-bun-adapter": "^1.2.2", diff --git a/server/common.ts b/server/common.ts index 41c94fb..ecbd261 100644 --- a/server/common.ts +++ b/server/common.ts @@ -1,11 +1,25 @@ +import _ from "lodash" +import { z } from "zod"; + +export const uint8 = z.number().nonnegative().lt(Math.pow(2, 8)) +export const uint16 = z.number().nonnegative().lt(Math.pow(2, 16)) +export const uint32 = z.number().nonnegative().lt(Math.pow(2, 32)) + +export const int8 = z.number().lt(Math.pow(2, 7)).gte(-Math.pow(2, 8)) +export const int16 = z.number().lt(Math.pow(2, 15)).gte(-Math.pow(2, 16)) +export const int32 = z.number().lt(Math.pow(2, 31)).gte(-Math.pow(2, 32)) + export function numberToBytes(num: number, bytesLength: number): Uint8Array { var array = new Uint8Array(bytesLength) - var i; - for (i = 0; i < bytesLength; i++) { + for (let i = 0; i < bytesLength; i++) { array[i] = num & (0xFF << (i << 3)) } return array } +export function randomFromArray(array: Array) { + return array[_.random(0, array.length - 1, false)] +} + diff --git a/server/database.test.ts b/server/database.test.ts index fc6f029..47dec42 100644 --- a/server/database.test.ts +++ b/server/database.test.ts @@ -1,10 +1,39 @@ import { test, expect } from "bun:test" import * as db from "./database.ts" +import _ from "lodash" +import { randomFromArray } from "./common.ts" +import { None, Ok } from "ts-results-es" test("DataBase", () => { const allTables = db.allTables() expect(allTables).toBeArray() expect(allTables).toEqual(["Users", "Boards"]) - expect(db.boardsNum()).toBe(0) + expect(db.BoardTable.count()).toBe(0) + expect(db.UserTable.count()).toBe(0) +}) + +test("Board Table", () => { + const boardsNumber = 10 + const rooms = ["A1", "A2"] + + // Try to find something empty + const findEmptyByID = db.BoardTable.find(_.random(0, boardsNumber)) + expect(findEmptyByID).toEqual(Ok(None)) + const findEmptyByName = db.BoardTable.find("Hello") + expect(findEmptyByName).toEqual(Ok(None)) + + + const boardsArray: Array = [] + for (let i = 0; i < boardsNumber; i++) { + boardsArray.push({ + id: _.random(0, 100), + name: `Board ${i}`, + room: randomFromArray(rooms), + ipv4: `192.168.172.${i}`, + port: _.random(0, 665535), + }) + } + + }) diff --git a/server/database.ts b/server/database.ts index 586dccc..a3c89cc 100644 --- a/server/database.ts +++ b/server/database.ts @@ -1,10 +1,10 @@ -import { Database } from "bun:sqlite"; +import { Database, type Changes } from "bun:sqlite"; import _ from "lodash"; import { Ok, Err, Result, None, Some, Option } from "ts-results-es"; import { z } from "zod"; const db = new Database("lab.sqlite", { strict: true }) -initDB(); +initDB(db); const boardSchema = z.object({ @@ -13,7 +13,7 @@ const boardSchema = z.object({ room: z.string(), ipv4: z.string().ip({ version: "v4" }), ipv6: z.string().ip({ version: "v6" }), - port: z.number().nonnegative(), + port: z.number().nonnegative().lte(65535), cmdID: z.number().nonnegative() }).partial({ ipv6: true, @@ -42,7 +42,7 @@ export function isUser(obj: any): obj is User { } -function initDB() { +function initDB(db: Database) { const tables = allTables() if (!tables.includes("Users")) { @@ -91,19 +91,22 @@ export function tableColumnName(table: string): Array { return columnName } -export function addBoard(board: Board): Result { - if (!isBoard(board)) { - return new Err("Wrong params type") - } +export namespace BoardTable { - if (board.id == 0) { - const idNum = boardsNum() - board.id = idNum - } else { + export function add(board: Board): Result { + if (!isBoard(board)) { + return new Err("Wrong type") + } - } + if (board.id == 0) { + const cnt = count() + board.id = cnt + 1 + } else if (includes(board.id)) { + return new Err("ID conflict") + } - const query = db.query(` + + const query = db.query(` INSERT INTO Boards VALUES (${board.id}, '${board.name}, @@ -112,83 +115,158 @@ export function addBoard(board: Board): Result { '${typeof board.ipv6 === "undefined" ? "NULL" : board.ipv6}', ${board.port}); `) - query.run() - return Ok(board) -} - -export function boardsNum(): number { - const query = db.query(`SELECT COUNT(*) FROM Boards`) - return query.values()[0][0] as number -} - -export function deleteBoard(name?: string): Result -export function deleteBoard(id?: number): Result -export function deleteBoard(board?: Board): Result -export function deleteBoard(arg: any): Result { - let retBoard - let condition: string - if (isBoard(arg)) { - retBoard = arg - - } else if (_.isNumber(arg)) { - retBoard = findBoard(arg) - - } else if (_.isString(arg)) { - retBoard = findBoard(arg) - - } else { - return new Err("Wrong Type") + return Ok(query.run()) } - const query = db.query(`DELETE FROM Boards WHERE id=${arg.id}`) - - return new Ok(retBoard) -} - -export function allBoards() { - const query = db.query(`SELECT * FROM Boards`) - const boards = query.all() - - query.finalize() - return boards -} - - -export function findBoard(name?: string): Result, "Wrong type"> -export function findBoard(id?: number): Result, "Wrong type"> -export function findBoard(arg: any): Result, "Wrong type"> { - let condition: string - if (_.isNumber(arg)) { - condition = `arg=${arg}` - - } else if (_.isString(arg)) { - condition = `name='${arg}'` - - } else { - return new Err("Wrong type") + export function addFromArray(array: Array): Result { + for (const item of array) { + const ret = add(item) + if (ret.isErr()) { + return new Err("Wrong type") + } + } + return new Ok() } - const query = db.query(`SELECT * FROM Boards WHERE ${condition}`) - - const spRet = boardSchema.safeParse(query.get()) - if (spRet.success) { - return new Ok(Some(spRet.data)) - } else { - return new Ok(None) + export function count(): number { + const query = db.query(`SELECT COUNT(*) FROM Boards`) + return query.values()[0][0] as number } + + export function remove(name?: string): Result + export function remove(id?: number): Result + export function remove(board?: Board): Result + export function remove(arg: any): Result { + let retBoard + let condition: string + if (isBoard(arg)) { + retBoard = _.cloneDeep(arg) + condition = `id=${arg.id}` + + } else if (_.isNumber(arg)) { + retBoard = find(arg) + if (retBoard.isOk() && retBoard.value.isSome()) { + retBoard = _.cloneDeep(retBoard.value.value) + condition = `id=${arg}` + } else { + return new Err("No such Board") + } + + } else if (_.isString(arg)) { + retBoard = find(arg) + if (retBoard.isOk() && retBoard.value.isSome()) { + retBoard = _.cloneDeep(retBoard.value.value) + condition = `name=${arg}` + } else { + return new Err("No such Board") + } + + } else { + return new Err("Wrong Type") + } + + const query = db.query(`DELETE FROM Boards WHERE ${condition}`) + query.run() + + return new Ok(retBoard) + } + + export function all() { + const query = db.query(`SELECT * FROM Boards`) + const boards = query.all() + + query.finalize() + return boards + } + + + export function find(name: string, room: string): Result, "Wrong type"> + export function find(id: number): Result, "Wrong type"> + export function find(arg1: any, arg2: any): Result, "Wrong type"> { + let condition: string + if (_.isNumber(arg1)) { + condition = `id=${arg1}` + + } else if (_.isString(arg1)) { + condition = `name='${arg1}'` + + } else { + return new Err("Wrong type") + + } + + const query = db.query(`SELECT * FROM Boards WHERE ${condition}`) + + const spRet = boardSchema.safeParse(query.get()) + + if (spRet.success) { + return new Ok(Some(spRet.data)) + } else { + return new Ok(None) + } + } + + export function includes(name?: string): Result + export function includes(id?: number): Result + export function includes(arg: any): Result { + let condition: string + if (_.isNumber(arg)) { + condition = `id=${arg}` + + } else if (_.isString(arg)) { + condition = `name='${arg}'` + + } else { + return new Err("Wrong type") + + } + + const query = db.query(`SELECT * FROM Boards WHERE ${condition}`) + + const spRet = boardSchema.safeParse(query.get()) + + if (spRet.success) { + return new Ok(true) + } else { + return new Ok(false) + } + } + +} + +export namespace UserTable { + + export function count(): number { + const query = db.query(`SELECT COUNT(*) FROM Users`) + return query.values()[0][0] as number + } + + + export function find(id: number): Result, "Wrong Type"> + export function find(name: string): Result, "Wrong Type"> + export function find(arg: any): Result, "Wrong Type"> { + let condition: string + if (_.isNumber(arg)) { + condition = `id=${arg}` + } else if (_.isString(arg)) { + condition = `name=${arg}` + } else { + return new Err("Wrong Type") + } + + const query = db.query(`SELECT * FROM Users WHERE name='${arg}'`) + + const spRet = userSchema.safeParse(query.get()) + + if (spRet.success) { + return new Ok(Some(spRet.data)) + } else { + return new Ok(None) + } + } + } -export function findUser(name: string): User { - const query = db.query(`SELECT * FROM Users WHERE name='${name}'`) - - const spRet = userSchema.safeParse(query.get()) - if (spRet.success) { - return spRet.data - } else { - throw new Error(`Failure: Not found ${name} User`) - } -} -