diff --git a/.typo-ci.yml b/.typo-ci.yml deleted file mode 100644 index 1ba55656..00000000 --- a/.typo-ci.yml +++ /dev/null @@ -1,5 +0,0 @@ -excluded_words: - - hydrooj -excluded_files: - - package.json - - .typo-ci.yml diff --git a/README.md b/README.md index e607aa26..a8cbe48b 100644 --- a/README.md +++ b/README.md @@ -7,18 +7,18 @@ ![GitHub contributors](https://img.shields.io/github/contributors/hydro-dev/Hydro) ![GitHub commit activity](https://img.shields.io/github/commit-activity/y/hydro-dev/Hydro) -Hydro是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。 +Hydro 是一个高效的信息学在线测评系统。特点:易于部署(且提供安装脚本),轻量,功能强大且易于扩展。 Also see previous version at [vijos/vj4](https://github.com/vijos/vj4) -[中文文档](https://hydro.js.org/) [English](./README-EN.md) +[Demo](https://hydro.ac/) [中文文档](https://hydro.js.org/) [English](./README-EN.md) -欢迎 star 本项目,这是对开发者的鼓励。 -项目的开发与维护需要资金,欢迎进行捐助。 -Hydro提供收费的功能定制服务,如您需要可与我们联系。 +如果觉得本项目对你有帮助,不妨点一下右上角的 star 哦() +项目的开发与维护需要资金,欢迎[进行捐助](https://pay.undefined.moe) 。 +Hydro 提供收费的功能定制服务,如您需要可与我们联系。 相关文档若说明的不够详细,请提交 Pull Request 或联系开发组说明。 -bug和功能建议请在 Issues 提出。 +bug 和功能建议请在 Issues 提出。 -[在 Gitpod 打开已配置完成的测试环境](https://gitpod.io/#https://github.com/hydro-dev/Hydro) +[在 Gitpod 打开测试环境](https://gitpod.io/#https://github.com/hydro-dev/Hydro) ## 联系我们 diff --git a/packages/hydrooj/test/db.ts b/packages/hydrooj/test/db.ts deleted file mode 100644 index 8ce02b96..00000000 --- a/packages/hydrooj/test/db.ts +++ /dev/null @@ -1,26 +0,0 @@ -import 'hydrooj/src/loader'; - -import * as bus from 'hydrooj/src/service/bus'; - -jest.mock('hydrooj/src/service/db'); - -export async function connect() { - const db = require('hydrooj/src/service/db'); - await db.start({}); - const scripts = require('hydrooj/src/upgrade').default; - let dbVer = 0; - const expected = scripts.length; - while (dbVer < expected) { - const func = scripts[dbVer]; - dbVer++; - if (typeof func !== 'function' || func.toString().includes('_FRESH_INSTALL_IGNORE')) continue; - // eslint-disable-next-line no-await-in-loop - await func(); - } -} - -export async function dispose() { - const db = require('hydrooj/src/service/db'); - await db.stop(); - bus.emit('app/exit'); -} diff --git a/packages/hydrooj/test/lib.crypto.spec.ts b/packages/hydrooj/test/lib.crypto.spec.ts deleted file mode 100644 index 588fd72e..00000000 --- a/packages/hydrooj/test/lib.crypto.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import 'hydrooj/src/loader'; - -import { md5, sha1 } from 'hydrooj/src/lib/crypto'; -import pwhash from 'hydrooj/src/lib/hash.hydro'; - -describe('crypto', () => { - const content1 = 'twd2akioi'; - const content2 = '陈志鹏爱吃玻璃。'; - - test('MD5', () => { - const result1 = '57b6a9bd92c0502714ecedc4a5ebf24c'; - const result2 = 'f598cb0738e7cd9efbbdf0ad7b6b42a7'; - expect(md5(content1)).toStrictEqual(result1); - expect(md5(content2)).toStrictEqual(result2); - }); - - test('SHA1', () => { - const result1 = 'bade50df188c338fae183cf3bde34fafaf590bc5'; - const result2 = '4d3fce39e3a163fe65263d8283ed3e98244fda42'; - expect(sha1(content1)).toStrictEqual(result1); - expect(sha1(content2)).toStrictEqual(result2); - }); - - test('PWHASH', () => { - const password1 = 'password1'; - const salt1 = '0326Bc23E6fac733K01g29fBBUSAj7O4'; - const salt2 = String.random(32); - const hash1 = '70a2db6a53ecd75d8d4b19d8647a416b4e812c1a6635c4a1f5069a00382fdcb6'; - expect(pwhash(password1, salt1)).toStrictEqual(hash1); - expect(pwhash(password1, salt2)).not.toEqual(hash1); - }); -}); diff --git a/packages/hydrooj/test/lib.validator.spec.ts b/packages/hydrooj/test/lib.validator.spec.ts deleted file mode 100644 index 4161d55c..00000000 --- a/packages/hydrooj/test/lib.validator.spec.ts +++ /dev/null @@ -1,104 +0,0 @@ -import 'hydrooj/src/loader'; - -import * as validator from 'hydrooj/src/lib/validator'; - -describe('Validator', () => { - test('uid', () => { - expect(validator.isUid('123')).toBeTruthy(); - expect(validator.isUid('123')).toBeTruthy(); - expect(validator.isUid('-456')).toBeTruthy(); - expect(validator.isUid('')).toBeFalsy(); - expect(validator.isUid('1.23')).toBeFalsy(); - expect(validator.isUid('xyz')).toBeFalsy(); - }); - - test('uname', () => { - expect(validator.isUname('twd2')).toBeTruthy(); - expect(validator.isUname('123twd3')).toBeTruthy(); - expect(validator.isUname('$%1234')).toBeTruthy(); - expect(validator.isUname('12<> { - expect(validator.isPassword('123twd3')).toBeTruthy(); - expect(validator.isPassword('12<> { - expect(validator.isEmail('ex@example.com')).toBeTruthy(); - expect(validator.isEmail('1+e-x@example.com')).toBeTruthy(); - expect(validator.isEmail('example.net@example.com')).toBeTruthy(); - expect(validator.isEmail('example:net@example.com')).toBeFalsy(); - expect(validator.isEmail('ex@examplecom')).toBeFalsy(); - expect(validator.isEmail('example.com')).toBeFalsy(); - expect(validator.isEmail('examplecom')).toBeFalsy(); - expect(validator.isEmail('1+e=x@example.com')).toBeFalsy(); - }); - - /* - test('domainId', () => { - expect(validator.is_domain_id('my_domain_1')).toBeTruthy(); - expect(validator.is_domain_id('My_Domain')).toBeTruthy(); - expect(validator.is_domain_id('MyDomain')).toBeTruthy(); - expect(validator.is_domain_id('myDomain')).toBeTruthy(); - expect(validator.is_domain_id('twd2')).toBeTruthy(); - expect(validator.is_domain_id('twd' * 10)).toBeTruthy(); - expect(validator.is_domain_id('C:\\a.txt')).toBeFalsy(); - expect(validator.is_domain_id('/etc/hosts')).toBeFalsy(); - expect(validator.is_domain_id('')).toBeFalsy(); - expect(validator.is_domain_id(' twd4')).toBeFalsy(); - expect(validator.is_domain_id('twd4\u3000')).toBeFalsy(); - expect(validator.is_domain_id('\ntwd4')).toBeFalsy(); - expect(validator.is_domain_id('22domain')).toBeFalsy(); - expect(validator.is_domain_id('22-Domain')).toBeFalsy(); - expect(validator.is_domain_id('My-Domain')).toBeFalsy(); - expect(validator.is_domain_id('dom')).toBeFalsy(); - expect(validator.is_domain_id('twd' * 500)).toBeFalsy(); - expect(validator.is_domain_id('twd\r\n2')).toBeFalsy(); - expect(validator.is_domain_id('$domain')).toBeFalsy(); - expect(validator.is_domain_id('12<> { - expect(validator.isRole('my_domain_1')).toBeTruthy(); - expect(validator.isRole('My_Domain')).toBeTruthy(); - expect(validator.isRole('MyDomain')).toBeTruthy(); - expect(validator.isRole('myDomain')).toBeTruthy(); - expect(validator.isRole('twd2')).toBeTruthy(); - expect(validator.isRole('twd'.repeat(10))).toBeTruthy(); - expect(validator.isRole('r0le')).toBeTruthy(); - expect(validator.isRole('1role')).toBeTruthy(); - expect(validator.isRole('C:\\a.txt')).toBeFalsy(); - expect(validator.isRole('/etc/hosts')).toBeFalsy(); - expect(validator.isRole('')).toBeFalsy(); - expect(validator.isRole(' twd4')).toBeFalsy(); - expect(validator.isRole('twd4\u3000')).toBeFalsy(); - expect(validator.isRole('\ntwd4')).toBeFalsy(); - expect(validator.isRole('My-Role')).toBeFalsy(); - expect(validator.isRole('twd'.repeat(90))).toBeFalsy(); - expect(validator.isRole('twd\r\n2')).toBeFalsy(); - expect(validator.isRole('$role')).toBeFalsy(); - expect(validator.isRole('role.admin')).toBeFalsy(); - expect(validator.isRole('12<> { - expect(validator.isContent('dummy_name')).toBeTruthy(); - expect(validator.isContent('x'.repeat(300))).toBeTruthy(); - expect(validator.isContent('c')).toBeTruthy(); - expect(validator.isContent('')).toBeFalsy(); - expect(validator.isContent('x'.repeat(700000))).toBeFalsy(); - }); -}); diff --git a/packages/hydrooj/test/model.problem.spec.ts b/packages/hydrooj/test/model.problem.spec.ts deleted file mode 100644 index e827a900..00000000 --- a/packages/hydrooj/test/model.problem.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import 'hydrooj/src/loader'; - -import { connect, dispose } from './db'; - -jest.setTimeout(30000); - -const DOMAIN_ID = 'system'; -const TITLE = 'dummy_title'; -const CONTENT = 'dummy_content'; -const CONTENT_1 = 'another_dummy_content'; -const UID = 22; -const PNAME = 'aaa'; - -describe('Model.Problem', () => { - let problem: typeof import('hydrooj/src/model/problem').default; - - beforeAll(async () => { - await connect(); - problem = require('hydrooj/src/model/problem').default; - }); - - test('add_get', async () => { - const pid = await problem.add(DOMAIN_ID, PNAME, TITLE, CONTENT, UID); - expect(pid).toBeTruthy(); - const pdoc = await problem.get(DOMAIN_ID, PNAME); - expect(pdoc.domainId).toStrictEqual(DOMAIN_ID); - expect(pdoc.title).toStrictEqual(TITLE); - expect(pdoc.content).toStrictEqual(CONTENT); - expect(pdoc.owner).toStrictEqual(UID); - expect(pdoc.docId).toStrictEqual(pid); - expect(pdoc.pid).toStrictEqual(PNAME); - const pdoc1 = await problem.get(DOMAIN_ID, pid); - expect(pdoc1).toStrictEqual(pdoc); - const pdocs = await problem.getMulti(DOMAIN_ID, {}).toArray(); - expect(pdocs.length).toStrictEqual(1); - expect(pdocs[0].docId).toStrictEqual(pid); - expect(pdocs[0].title).toStrictEqual(TITLE); - }); - - test('edit', async () => { - const pid = await problem.add(DOMAIN_ID, PNAME, TITLE, CONTENT, UID); - const pdoc = await problem.edit(DOMAIN_ID, pid, { content: CONTENT_1 }); - expect(pdoc.content).toStrictEqual(CONTENT_1); - }); - - /* FIXME doesn't work as storage isn't mocked yet - test('del', async () => { - const pid = await problem.add(DOMAIN_ID, PNAME, TITLE, CONTENT, UID); - let pdocs = await problem.getMulti(DOMAIN_ID, {}).toArray(); - let count = pdocs.length; - await problem.del(DOMAIN_ID, pid); - pdocs = await problem.getMulti(DOMAIN_ID, {}).toArray(); - expect(pdocs.length).toStrictEqual(count - 1); - }) - */ - - afterAll(dispose); -}); diff --git a/packages/hydrooj/test/model.user.spec.ts b/packages/hydrooj/test/model.user.spec.ts deleted file mode 100644 index a3f8406b..00000000 --- a/packages/hydrooj/test/model.user.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import 'hydrooj/src/loader'; - -import { PRIV } from 'hydrooj/src/model/builtin'; -import * as bus from 'hydrooj/src/service/bus'; -import { connect, dispose } from './db'; - -jest.setTimeout(30000); - -describe('Model.User', () => { - let user: typeof import('hydrooj/src/model/user').default; - - beforeAll(async () => { - await connect(); - user = require('hydrooj/src/model/user').default; - require('hydrooj/src/model/setting'); - await bus.serial('app/started'); - }); - - test('create', async () => { - const uid = await user.create('i@undefined.moe', 'undefined', '123456'); - expect(uid).toStrictEqual(2); - }); - - test('getById', async () => { - const udoc = await user.getById('system', 2); - expect(udoc.mail).toStrictEqual('i@undefined.moe'); - }); - - test('getByEmail', async () => { - const udoc = await user.getByEmail('system', 'i@undefined.moe'); - expect(udoc.uname).toStrictEqual('undefined'); - }); - - test('getByUname', async () => { - const udoc = await user.getByUname('system', 'undefined'); - expect(udoc.mail).toStrictEqual('i@undefined.moe'); - }); - - test('createWithExtraArgs', async () => { - const uid1 = await user.create('test@undefined.moe', 'test', '123456', -1, '127.0.0.1', -1); - expect(uid1).toStrictEqual(-1); - }); - - test('getList', async () => { - const udoc1 = await user.getList('system', [-1, 1]); - expect(udoc1[-1].uname).toStrictEqual('test'); - expect(udoc1[-1].hasPriv(PRIV.PRIV_MANAGE_ALL_DOMAIN)).toStrictEqual(true); - }); - - test('getPrefixList', async () => { - const udocs = await user.getPrefixList('system', 'u', 1); - expect(udocs.length).toStrictEqual(1); - expect(udocs[0].uname).toStrictEqual('undefined'); - }); - - afterAll(dispose); -}); diff --git a/packages/hydrooj/test/utils.spec.ts b/packages/hydrooj/test/utils.spec.ts deleted file mode 100644 index f660f2c6..00000000 --- a/packages/hydrooj/test/utils.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import 'hydrooj/src/loader'; - -import * as utils from 'hydrooj/src/utils'; - -describe('Utils', () => { - test('Array.isDiff', () => { - expect(Array.isDiff([1], [2])).toBeTruthy(); - expect(Array.isDiff([1, 2, 3], [1, 2])).toBeTruthy(); - expect(Array.isDiff(['1'], [1])).toBeTruthy(); - expect(Array.isDiff(['2'], [])).toBeTruthy(); - expect(Array.isDiff([1], [1])).toBeFalsy(); - expect(Array.isDiff([1, 2], [2, 1])).toBeFalsy(); - }); - - test('Date.format', () => { - const date = new Date('1926-08-17 00:00:00'); - expect(date.format()).toStrictEqual('1926-08-17 00:00:00'); - expect(date.format('%Y-%m+%d')).toStrictEqual('1926-08+17'); - }); - - test('Math.sum', () => { - expect(Math.sum(1, 2, 3)).toStrictEqual(6); - expect(Math.sum([1, 2], 3)).toStrictEqual(6); - expect(Math.sum(-1, 2, 3)).toStrictEqual(4); - expect(Math.sum()).toStrictEqual(0); - }); - - test('Set.isSuperset', () => { - const setA = new Set([1, 2, 3]); - const setB = new Set([1]); - const setC = new Set([2]); - const setD = new Set(); - expect(Set.isSuperset(setA, setA)).toBeTruthy(); - expect(Set.isSuperset(setA, setB)).toBeTruthy(); - expect(Set.isSuperset(setB, setA)).toBeFalsy(); - expect(Set.isSuperset(setB, setC)).toBeFalsy(); - expect(Set.isSuperset(setA, setD)).toBeTruthy(); - }); - - test('Set.union', () => { - const setA = new Set([1, 2, 3]); - const setB = new Set([2]); - const setC = new Set([4]); - const setD = new Set([1, 2, 3, 4]); - expect(Set.union(setA, setB)).toStrictEqual(setA); - expect(Set.union(setA, setC)).toStrictEqual(setD); - }); - - test('Set.intersection', () => { - const setA = new Set([1, 2, 3]); - const setB = new Set([2]); - const setC = new Set([4]); - const setD = new Set(); - expect(Set.intersection(setA, setB)).toStrictEqual(setB); - expect(Set.intersection(setA, setC)).toStrictEqual(setD); - expect(Set.intersection(setA, setD)).toStrictEqual(setD); - }); - - test('parseTimeMs', () => { - expect(utils.parseTimeMS('1000ms')).toStrictEqual(1000); - expect(utils.parseTimeMS('1s')).toStrictEqual(1000); - expect(utils.parseTimeMS('1.5s')).toStrictEqual(1500); - expect(utils.parseTimeMS('13000us')).toStrictEqual(13); - }); - - test('parseMemoryMB', () => { - expect(utils.parseMemoryMB('1mb')).toStrictEqual(1); - expect(utils.parseMemoryMB('10kb')).toStrictEqual(1); - expect(utils.parseMemoryMB('0.2g')).toStrictEqual(205); - }); - - test('isClass', () => { - const classA = class { }; - const classB = function a() { }; - classB.prototype.get = function a() { return 1; }; - const funcA = function a() { }; - expect(utils.isClass(classA)).toBeTruthy(); - expect(utils.isClass(classB)).toBeTruthy(); - expect(utils.isClass(funcA)).toBeFalsy(); - }); -});